From b10dbe5c727eedace5c84addd0573bfa1b0c027a Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 11 Apr 2012 13:35:32 -0300 Subject: bug: C libraries must be unloaded after all other finalizers have run, because a finalizer may use a C function from a C library --- loadlib.c | 74 +++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 33 deletions(-) (limited to 'loadlib.c') diff --git a/loadlib.c b/loadlib.c index f2d7fe3c..2526096c 100644 --- a/loadlib.c +++ b/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.107 2011/11/30 12:58:57 roberto Exp roberto $ +** $Id: loadlib.c,v 1.108 2011/12/12 16:34:03 roberto Exp roberto $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -92,9 +92,9 @@ #define LUA_OFSEP "_" -#define LIBPREFIX "LOADLIB: " +/* table (in the registry) that keeps handles for all loaded C libraries */ +#define CLIBS "_CLIBS" -#define POF LUA_POF #define LIB_FAIL "open" @@ -248,48 +248,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #endif - -static void **ll_register (lua_State *L, const char *path) { - void **plib; - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ - if (!lua_isnil(L, -1)) /* is there an entry? */ - plib = (void **)lua_touserdata(L, -1); - else { /* no entry yet; create one */ - lua_pop(L, 1); /* remove result from gettable */ - plib = (void **)lua_newuserdata(L, sizeof(const void *)); - *plib = NULL; - luaL_setmetatable(L, "_LOADLIB"); - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_pushvalue(L, -2); - lua_settable(L, LUA_REGISTRYINDEX); - } +static void *ll_checkclib (lua_State *L, const char *path) { + void *plib; + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ return plib; } +static void ll_addtoclib (lua_State *L, const char *path, void *plib) { + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ +} + + /* -** __gc tag method: calls library's `ll_unloadlib' function with the lib -** handle +** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib +** handles in list CLIBS */ static int gctm (lua_State *L) { - void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); - if (*lib) ll_unloadlib(*lib); - *lib = NULL; /* mark library as closed */ + int n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + ll_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } return 0; } static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { - void **reg = ll_register(L, path); - if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); - if (*reg == NULL) return ERRLIB; /* unable to load library */ + void *reg = ll_checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) { /* must load library? */ + reg = ll_load(L, path, *sym == '*'); + if (reg == NULL) return ERRLIB; /* unable to load library */ + ll_addtoclib(L, path, reg); + } if (*sym == '*') { /* loading only library (no function)? */ lua_pushboolean(L, 1); /* return 'true' */ return 0; /* no errors */ } else { - lua_CFunction f = ll_sym(L, *reg, sym); + lua_CFunction f = ll_sym(L, reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); /* else create new function */ @@ -418,12 +424,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) { if (mark) { int stat; funcname = lua_pushlstring(L, modname, mark - modname); - funcname = lua_pushfstring(L, POF"%s", funcname); + funcname = lua_pushfstring(L, LUA_POF"%s", funcname); stat = ll_loadfunc(L, filename, funcname); if (stat != ERRFUNC) return stat; modname = mark + 1; /* else go ahead and try old-style name */ } - funcname = lua_pushfstring(L, POF"%s", modname); + funcname = lua_pushfstring(L, LUA_POF"%s", modname); return ll_loadfunc(L, filename, funcname); } @@ -672,10 +678,12 @@ static const lua_CFunction searchers[] = LUAMOD_API int luaopen_package (lua_State *L) { int i; - /* create new type _LOADLIB */ - luaL_newmetatable(L, "_LOADLIB"); + /* create table CLIBS to keep track of loaded C libraries */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); + lua_createtable(L, 0, 1); /* metatable for CLIBS */ lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); /* create `package' table */ luaL_newlib(L, pk_funcs); /* create 'searchers' table */ -- cgit v1.2.3-55-g6feb