lua-users home
lua-l archive

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


On Mon, Oct 16, 2006 at 03:27:30PM -0400, Glenn Maynard wrote:
> longjmp is incompatible with C++ destructors, and will result in leaks.

It is also "incompatible" with malloc/free, this:

> int mybinding(lua_State *L)
> {
>     std::string s1 = luaL_checkstring(L, 1);
>     std::string s2 = luaL_checkstring(L, 2);
>     ...
> }

is same problem as:

int mybinding(lua_State *L)
{
    char* s1 = strdup(luaL_checkstring(L, 1));
    char* s2 = strdup(luaL_checkstring(L, 2)); // -- leaks s1 on error
    ...
}

So the techniques used for C code apply equally here, simple is:

int mybinding(lua_State *L)
{
	// make checks that may error() so nothing will error() later
	luaL_checkstring(L, 1);
	luaL_checkstring(L, 2);
	...

	// allocate resources
    std::string s1 = lua_tostring(L, 1);
    std::string s2 = lua_tostring(L, 2);
    ...

	// do things that will not error()

....

	// free resources
....
}

Other idiom, as Rici (?) suggested and used in the PIL, is to first
create something that WILL be garbage-collected, like a user-data, then
put your two std::string inside the user-data. If lua longjmps out of
your code, lua will still have the UD on the stack, and lua will know it
needs to be garbage collected, and in the __gc metamethod you can
destroy the s1 and s2.

I guess if code is large enough, then refactor into parts of code that
allocates resources, and into a function that uses those resources and
may error(). pcall the function that may error.

Its hard to have the benefits of C++ automatic resource freeing with
exceptions, without paying the costs for exceptions!

Cheers,
Sam