mirror of
https://github.com/lua/lua.git
synced 2026-08-09 22:59:34 +00:00
Bug: GC checks stack space before running finalizer
If some stack does not have a minimum available space, the GC defers calling a finalizer until the next cycle. That avoids errors while running a finalizer that the programmer cannot control.
This commit is contained in:
21
ldo.c
21
ldo.c
@@ -205,6 +205,25 @@ l_noret luaD_errerr (lua_State *L) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether stacks have enough space to run a simple function (such
|
||||
** as a finalizer): At least BASIC_STACK_SIZE in the Lua stack, two
|
||||
** available CallInfos, and two "slots" in the C stack.
|
||||
*/
|
||||
int luaD_checkminstack (lua_State *L) {
|
||||
if (getCcalls(L) >= LUAI_MAXCCALLS - 2)
|
||||
return 0; /* not enough C-stack slots */
|
||||
if (L->ci->next == NULL && luaE_extendCI(L, 0) == NULL)
|
||||
return 0; /* unable to allocate first ci */
|
||||
if (L->ci->next->next == NULL && luaE_extendCI(L, 0) == NULL)
|
||||
return 0; /* unable to allocate second ci */
|
||||
if (L->stack_last.p - L->top.p >= BASIC_STACK_SIZE)
|
||||
return 1; /* enough (BASIC_STACK_SIZE) free slots in the Lua stack */
|
||||
else /* try to grow stack to a size with enough free slots */
|
||||
return luaD_growstack(L, BASIC_STACK_SIZE, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Reallocate the stack to a new size, correcting all pointers into it.
|
||||
** In ISO C, any pointer use after the pointer has been deallocated is
|
||||
@@ -503,7 +522,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
||||
|
||||
|
||||
|
||||
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L))
|
||||
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L, 1))
|
||||
|
||||
|
||||
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
|
||||
|
||||
1
ldo.h
1
ldo.h
@@ -80,6 +80,7 @@ LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
|
||||
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
||||
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
||||
LUAI_FUNC void luaD_inctop (lua_State *L);
|
||||
LUAI_FUNC int luaD_checkminstack (lua_State *L);
|
||||
|
||||
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
|
||||
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||
|
||||
7
lgc.c
7
lgc.c
@@ -1242,7 +1242,7 @@ static void finishgencycle (lua_State *L, global_State *g) {
|
||||
correctgraylists(g);
|
||||
checkSizes(L, g);
|
||||
g->gcstate = GCSpropagate; /* skip restart */
|
||||
if (!g->gcemergency)
|
||||
if (g->tobefnz != NULL && !g->gcemergency && luaD_checkminstack(L))
|
||||
callallpendingfinalizers(L);
|
||||
}
|
||||
|
||||
@@ -1632,11 +1632,12 @@ static lu_mem singlestep (lua_State *L) {
|
||||
break;
|
||||
}
|
||||
case GCScallfin: { /* call remaining finalizers */
|
||||
if (g->tobefnz && !g->gcemergency) {
|
||||
if (g->tobefnz && !g->gcemergency && luaD_checkminstack(L)) {
|
||||
g->gcstopem = 0; /* ok collections during finalizers */
|
||||
work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST;
|
||||
}
|
||||
else { /* emergency mode or no more finalizers */
|
||||
else { /* no more finalizers or emergency mode or no enough stack
|
||||
to run finalizers */
|
||||
g->gcstate = GCSpause; /* finish collection */
|
||||
work = 0;
|
||||
}
|
||||
|
||||
17
lstate.c
17
lstate.c
@@ -102,14 +102,19 @@ LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
|
||||
}
|
||||
|
||||
|
||||
CallInfo *luaE_extendCI (lua_State *L) {
|
||||
CallInfo *luaE_extendCI (lua_State *L, int err) {
|
||||
CallInfo *ci;
|
||||
lua_assert(L->ci->next == NULL);
|
||||
ci = luaM_new(L, CallInfo);
|
||||
lua_assert(L->ci->next == NULL);
|
||||
L->ci->next = ci;
|
||||
ci = luaM_reallocvector(L, NULL, 0, 1, CallInfo);
|
||||
if (l_unlikely(ci == NULL)) { /* allocation failed? */
|
||||
if (err)
|
||||
luaM_error(L); /* raise the error */
|
||||
return NULL; /* else only report it */
|
||||
}
|
||||
ci->next = L->ci->next;
|
||||
ci->previous = L->ci;
|
||||
ci->next = NULL;
|
||||
L->ci->next = ci;
|
||||
if (ci->next)
|
||||
ci->next->previous = ci;
|
||||
ci->u.l.trap = 0;
|
||||
L->nci++;
|
||||
return ci;
|
||||
|
||||
2
lstate.h
2
lstate.h
@@ -395,7 +395,7 @@ union GCUnion {
|
||||
|
||||
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
||||
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
||||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
||||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L, int err);
|
||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
||||
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
||||
|
||||
Reference in New Issue
Block a user