Skip to content

Commit

Permalink
posix/syslog: fix releasing ident string
Browse files Browse the repository at this point in the history
The openlog() function stores the ident string in a userdata. Syslog stores a
reference to this dynamically allocated string and uses it when printing log
messages. When Lua exits closelog() is not automatically called causing syslog
to keep the reference while the memory itself is freed. This caused segfaults
when syslog was called from C code after Lua exited.

A __gc metamethod was added to the ident field that automatically calls
closelog(). If closelog() is called explicitly or openlog() is called for a
second time the __gc metamethod is removed from ident to prevent closelog()
from being called for a second time, possibly at a later point in time after
openlog() has been called again.
  • Loading branch information
Dirk Feytons committed Jun 6, 2017
1 parent e9a483d commit a55ef1d
Showing 1 changed file with 30 additions and 15 deletions.
45 changes: 30 additions & 15 deletions src/C/posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,28 @@ static int l_inet_pton(lua_State *L)
}
}

/**
* Close the connection being used to write to the system logger.
*
* @function closelog
* @see closelog(3)
*/
static int l_closelog(lua_State *L)
{
closelog();
// The stored ident string can be unanchored now but the metatable with __gc must be removed to avoid this function being called again later when the ident string is actually GC'd.
// That would potentially undo a more recent call to openlog() leading to unexpected log message format.
lua_getfield(L, LUA_ENVIRONINDEX, "ident");
if (!lua_isnil(L, -1))
{
lua_pushnil(L);
lua_setmetatable(L, -2);
lua_pushnil(L);
lua_setfield(L, LUA_ENVIRONINDEX, "ident");
}
return 0;
}

/**
* Open a connection to the system logger for a program.
*
Expand All @@ -432,9 +454,16 @@ static int l_openlog(lua_State *L)
int option = luaL_checkint(L, 2);
int facility = luaL_checkint(L, 3);

// Before storing a (new) ident string make sure the old one is fully cleaned up.
// We don't want the GC to kick in later and mess with the ident string that is in use at that moment.
l_closelog(L);

char *identcp = lua_newuserdata(L, len + 1);
strcpy(identcp, ident);
// store it in our environment table, so that it is not garbage collected
lua_createtable(L, 0, 1);
lua_pushcfunction(L, l_closelog);
lua_setfield(L, -2, "__gc");
lua_setmetatable(L, -2);
lua_setfield(L, LUA_ENVIRONINDEX, "ident");

openlog(identcp, option, facility);
Expand All @@ -457,20 +486,6 @@ static int l_syslog(lua_State *L)
return 0;
}

/**
* Close the connection being used to write to the system logger.
*
* @function closelog
* @see closelog(3)
*/
static int l_closelog(lua_State *L)
{
lua_pushnil(L);
lua_setfield(L, LUA_ENVIRONINDEX, "ident");
closelog();
return 0;
}

static const luaL_reg s_tch_posix[] =
{
{ "clock_gettime", l_clock_gettime },
Expand Down

0 comments on commit a55ef1d

Please sign in to comment.