lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


FWIW, I use a C++ class to encapsulate all my C++/Lua interactions. On each
method on this class, I have macros that assert zero stack growth and (in
release mode) adjust the stack correctly. This has alleviated all such
problems from our code base.

Eric

> -----Original Message-----
> From: owner-lua-l@tecgraf.puc-rio.br
> [mailto:owner-lua-l@tecgraf.puc-rio.br]On Behalf Of Bruno Silva
> Sent: Tuesday, August 21, 2001 1:40 PM
> To: Multiple recipients of list
> Subject: RE: lua calling exit()
>
>
> > > I have a newbie question then: how should I call this function in an
> > > *error-proof* way?
> > >
> > >         -- takes 2 strings, returns a boolean
> > >         handled = Function (arg1, arg2)
> > >
> > >         // calls Function
> > >         lua_getglobal(s_lua, "Function");
> > >         lua_pushstring (s_lua, arg1);
> > >         lua_pushstring (s_lua, arg2);
> > >         if (lua_call (s_lua, 2, 1) == 0)
> > >         {
> > >             handled = (bool) lua_tonumber (s_lua, -1);
> > >             lua_pop (s_lua, 1);
> > >         }
> >
> > That is difficult.  lua_getglobal, lua_pushstring and lua_tonumber
> > may raise an error.  Even lua_pushcfunction/cclosure may raise one
> > so it's pretty difficult to call something in a secure way.  A
> > lua_catch function (similar to luaD_runprotected) would help a lot.
> >
> This is unfortunate. As Luiz pointed out though, this is less of a
> problem when the functions being called are written in Lua. So is the
> following any safer?
>
> 	lua_dostring (L, "return Function (arg1, arg2)");
>
> This leaves whatever values "Function" returns on the stack and would
> allow leaking if Function is not properly written.
>
> Luiz wrote:
> > >This must work (i.e., leave a clean stack) regardless of what
> > >"Function" evaluates to and whether the execution of "Function"
> > >succeeded or failed for whatever reasons.
> >
> > If you need this, I think the simplest solution is use lua_rawcall
> instead > of lua_call (same arguments, but lua_rawcall is void). In this
> case, if
> > "Function" fails, then you'll get an ordinary error through
> _ERRORMESSAGE.
> >
> Well, it then immediately calls exit() on my app. Are you assuming that
> the lua_rawcall is itself protected by the lua_call() trick? If so, then
> I guess it would work.
>
> Thanks for all the info. Bottom line for me so far is that we need to be
> extra careful with the stack. Lua can kill the app mercilessly when a
> stack overflow occurs, which is unacceptable for us, so we need to wrap
> all Lua API usage with a lua_call. I am planning to write a convenience
> class that provides this behavior, and change the Lua sources to make
> sure no Lua API calls can happen outside this context (that is, one that
> doesn't have a setjmp to jump back to).
>
> Is it possible to handle breakrun's in a different manner, even if it
> involves dumping the entire Lua context?
>
> In case anybody cares, I threw the following class together to help
> reduce the occurrence of these problems. It fairly simple and certainly
> not fail proof but helps catching certain careless uses of the stack.
>
> Bruno
>
> //
> // This class helps control lua stack leaks and underflows, use as:
> //   { LUA_SAFE_STACK_BLOCK(L); /* any lua code */ }
>
> #define LUA_MAKE_BLOCK_NAME(x)  _LUA_BLOCK_NAME_##x##_
> // __COUNTER__ is MS specific, but you don't really need it
> #define LUA_SAFE_STACK_BLOCK(LuaState) CLuaSafeStack
> LUA_MAKE_BLOCK_NAME(__COUNTER__) (LuaState)
>
> class CLuaSafeStack
> {
>   public:
>     CLuaSafeStack (lua_State* L)
>         : m_lua (L)
>         {
>             m_top = lua_gettop (m_lua);
>             if (m_top < 0)
>             {
>                 ASSERTMSG (false, _T("Lua stack underflow, fixed"));
>                 m_top = 0;
>                 lua_settop (m_lua, m_top);
>             }
>         }
>
>     ~CLuaSafeStack (void)
>         {
>             int endtop = lua_gettop (m_lua);
>             if (endtop != m_top)    // stack leak
>             {
>                 if (endtop < 0)
>                     ASSERTMSG (false, _T("Lua stack underflow, fixed"));
>                 else
>                     ASSERTMSG (false, _T("Lua stack leak, cleaned up"));
>                 // fix the stack to avoid any leaks (should not be
> needed)
>                 lua_settop (m_lua, m_top);
>             }
>         }
>   protected:
>     lua_State* m_lua;
>     int m_top;
> };