lua-users home
lua-l archive

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


Mike Pall already addressed the specific points regarding luaL_Buffer.

Another approach to getting exception safety here would be to allocate a
userdata in place of the malloc call. If the userdata is only referenced
from the Lua stack (but is referenced throughout your routine), then clean
up is automatic.

static int get_data(lua_State* L)
{
  char* buffer;
  int n = luaL_optint(L, 1, 512 /* some arbitrary default value */);

  buffer = (char*) lua_newuserdata( L, n );
  n = read_data(L, buffer, n);
        /* Include L so that we can throw Lua exceptions. */
  lua_pushlstring(L, buffer, n);
  return 1;
}

The downside is that now you drive memory usage and the GC harder since even
in the non-exception case, you don't dispose of the data promptly. The fix
for that is to define a proxy userdata object that holds the malloc result
and frees it in its __gc method but allows for premature explicit freeing.
That still, however, allocates an extra userdata object per pass through the
routine. If it really became an issue, then you would want to maintain a
cache of such stub userdata objects -- a cache of one might well be
sufficient.

One other downside to the proxy mechanism -- though probably not all that
severe in this case since generally things will get cleaned up rapidly -- is
that Lua's storage estimates will only see the pointer and not the memory to
which it refers.

Mark

on 7/20/07 2:16 AM, Dirk Feytons at dirk.feytons@gmail.com wrote:

> Hi,
> 
> I have the following situation: a C function that is called from Lua
> to retrieve a variable-size block of data from somewhere in my
> application. In code:
> 
> static int get_data(lua_State* L)
> {
>   char* buffer;
>   int n = luaL_optint(L, 1, 512 /* some arbitrary default value */);
> 
>   buffer = malloc(n);
>   if (!buffer)
>     return luaL_error(L, "malloc() failed");
>   n = read_data(buffer, n);
>   lua_pushlstring(L, buffer, n);
>   free(buffer);
>   return 1;
> }
> 
> A potential problem I see with this is that if lua_pushlstring()
> raises an error I leak the buffer. The chance that this happens is
> rather small but since this code will run on an embedded platform I
> really can't afford it.
> 
> I was looking at the luaL_Buffer mechanism. I know it is intended for
> collecting lots of small strings but luaL_prepbuffer() seems useful
> for my scenario. Could I use this to allocate space and pass the
> pointer to the read_data() function, then do a luaL_addsize() and
> luaL_pushresult()? Is it guaranteed that if some Lua function raises
> an error the luaL_Buffer memory is freed?