Print errors from __gc finalizers instead of rethrowing them.

Finalizers are not supposed to throw errors -- this is undefined behavior.
Lua 5.1 - 5.3 and (previously) LuaJIT rethrow the error. This randomly
breaks some unrelated code that just happens to do an allocation. Bad.
Lua 5.4 catches the error and emits a warning instead. But warnings are
not enabled by default, so it fails silently. Even worse.
LuaJIT (now) catches the error and emits a VM event. The default event
handler function prints "ERROR in finalizer: ...".
Set a custom handler function with: jit.attach(handler, "errfin")
This commit is contained in:
Mike Pall
2023-04-16 18:13:48 +02:00
parent 8bbd58e534
commit 1c27912705
4 changed files with 64 additions and 28 deletions

View File

@@ -21,6 +21,7 @@
#include "lj_state.h"
#include "lj_trace.h"
#include "lj_lib.h"
#include "lj_vmevent.h"
#if LJ_TARGET_POSIX
#include <sys/wait.h>
@@ -318,6 +319,18 @@ static int panic(lua_State *L)
return 0;
}
#ifndef LUAJIT_DISABLE_VMEVENT
static int error_finalizer(lua_State *L)
{
const char *s = lua_tostring(L, -1);
fputs("ERROR in finalizer: ", stderr);
fputs(s ? s : "?", stderr);
fputc('\n', stderr);
fflush(stderr);
return 0;
}
#endif
#ifdef LUAJIT_USE_SYSMALLOC
#if LJ_64 && !LJ_GC64 && !defined(LUAJIT_USE_VALGRIND)
@@ -339,7 +352,15 @@ static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
LUALIB_API lua_State *luaL_newstate(void)
{
lua_State *L = lua_newstate(mem_alloc, NULL);
if (L) G(L)->panic = panic;
if (L) {
G(L)->panic = panic;
#ifndef LUAJIT_DISABLE_VMEVENT
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
lua_pushcfunction(L, error_finalizer);
lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
#endif
}
return L;
}
@@ -353,7 +374,15 @@ LUALIB_API lua_State *luaL_newstate(void)
#else
L = lua_newstate(LJ_ALLOCF_INTERNAL, NULL);
#endif
if (L) G(L)->panic = panic;
if (L) {
G(L)->panic = panic;
#ifndef LUAJIT_DISABLE_VMEVENT
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
lua_pushcfunction(L, error_finalizer);
lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
#endif
}
return L;
}