lua-users home
lua-l archive

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



Am 09.05.2016 um 15:37 schrieb Roberto Ierusalimschy <roberto@inf.puc-rio.br>:

I would like to open a discussion on best practices for preventing memory leaks in C programs using the Lua API.

Consider the following code snippet:

char *s = malloc(32);
snprintf(s, 32, "bumblebee");
lua_pushstring(L, s);
free(s);

lua_pushstring() could raise an error (e.g. under memory pressure) and then the subsequent free(s) would not be called, leaking the memory.

One could use lua_newuserdata() instead of malloc, but this works only if the memory is allocated by our own code, it does not work where the memory is allocated e.g. by a third party library.

So a possible way could be to create a metatable containing a __gc method, then allocating a small userdata value containging only a pointer to the allocated data. The __gc method could then free the memory, even if lua_pushstring() fails.

Is it worth the effort?  How do others (you) handle this kind of possible errors?

My personal take on this is, btw:  I don't care as I long as I don't reference NULL pointers.  If we are under memory pressure and functions like lua_pushstring() are starting to fail, we will be in much deeper trouble anyway soon... ymmv, opinions very welcome.

I think both options are valid. If you are writing a public library,
I would go the first way; often this userdata has some useful meaning
to be exposed in Lua. As an example, streams (FILE*) in the I/O library
follow this pattern.

As we are talking about a public library indeed, I guess I will have to go the
extra mile...

So above example would essentially become

char *s = lua_newuserdata(L, 32);
snprintf(s, 32, "bumblebee");
lua_pushstring(L, s);

This prevents a memory leak if lua_pushstring() raises an error, but I will end
up with a number of rather small allocations that are only used for a short
period of time.  Wouldn't it be nice to have a explicit call in the Lua API to
free a userdata value immediately, e.g.

char *s = lua_newuserdata(L, 32);
snprintf(s, 32, "bumblebee");
lua_pushstring(L, s);
lua_freeuserdata(s)

Or do you think the garbage colletor overhead can be neglected?


For your own code (not to be used by others), the second line is fine,
too. Even if your pogram does not crash under huge memory pressure,
Linux will crash it for you anyway...

-- Roberto