mirror of https://github.com/rusefi/lua.git
Bug: finalizer calling exit can corrupt finalization order
'os.exit' can call lua_close again, separating new finalizers created after all previous finalizers were already separated.
This commit is contained in:
parent
86ec152433
commit
597a53bbc6
10
lgc.c
10
lgc.c
|
@ -907,7 +907,7 @@ static void GCTM (lua_State *L) {
|
||||||
int status;
|
int status;
|
||||||
lu_byte oldah = L->allowhook;
|
lu_byte oldah = L->allowhook;
|
||||||
int oldgcstp = g->gcstp;
|
int oldgcstp = g->gcstp;
|
||||||
g->gcstp = GCSTPGC; /* avoid GC steps */
|
g->gcstp |= GCSTPGC; /* avoid GC steps */
|
||||||
L->allowhook = 0; /* stop debug hooks during GC metamethod */
|
L->allowhook = 0; /* stop debug hooks during GC metamethod */
|
||||||
setobj2s(L, L->top++, tm); /* push finalizer... */
|
setobj2s(L, L->top++, tm); /* push finalizer... */
|
||||||
setobj2s(L, L->top++, &v); /* ... and its argument */
|
setobj2s(L, L->top++, &v); /* ... and its argument */
|
||||||
|
@ -1011,7 +1011,8 @@ static void correctpointers (global_State *g, GCObject *o) {
|
||||||
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
if (tofinalize(o) || /* obj. is already marked... */
|
if (tofinalize(o) || /* obj. is already marked... */
|
||||||
gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */
|
gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */
|
||||||
|
(g->gcstp & GCSTPCLS)) /* or closing state? */
|
||||||
return; /* nothing to be done */
|
return; /* nothing to be done */
|
||||||
else { /* move 'o' to 'finobj' list */
|
else { /* move 'o' to 'finobj' list */
|
||||||
GCObject **p;
|
GCObject **p;
|
||||||
|
@ -1502,14 +1503,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
|
||||||
*/
|
*/
|
||||||
void luaC_freeallobjects (lua_State *L) {
|
void luaC_freeallobjects (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
g->gcstp = GCSTPGC;
|
g->gcstp = GCSTPCLS; /* no extra finalizers after here */
|
||||||
luaC_changemode(L, KGC_INC);
|
luaC_changemode(L, KGC_INC);
|
||||||
separatetobefnz(g, 1); /* separate all objects with finalizers */
|
separatetobefnz(g, 1); /* separate all objects with finalizers */
|
||||||
lua_assert(g->finobj == NULL);
|
lua_assert(g->finobj == NULL);
|
||||||
g->gcstp = 0;
|
|
||||||
callallpendingfinalizers(L);
|
callallpendingfinalizers(L);
|
||||||
deletelist(L, g->allgc, obj2gco(g->mainthread));
|
deletelist(L, g->allgc, obj2gco(g->mainthread));
|
||||||
deletelist(L, g->finobj, NULL);
|
lua_assert(g->finobj == NULL); /* no new finalizers */
|
||||||
deletelist(L, g->fixedgc, NULL); /* collect fixed objects */
|
deletelist(L, g->fixedgc, NULL); /* collect fixed objects */
|
||||||
lua_assert(g->strt.nuse == 0);
|
lua_assert(g->strt.nuse == 0);
|
||||||
}
|
}
|
||||||
|
|
1
lgc.h
1
lgc.h
|
@ -154,6 +154,7 @@
|
||||||
*/
|
*/
|
||||||
#define GCSTPUSR 1 /* bit true when GC stopped by user */
|
#define GCSTPUSR 1 /* bit true when GC stopped by user */
|
||||||
#define GCSTPGC 2 /* bit true when GC stopped by itself */
|
#define GCSTPGC 2 /* bit true when GC stopped by itself */
|
||||||
|
#define GCSTPCLS 4 /* bit true when closing Lua state */
|
||||||
#define gcrunning(g) ((g)->gcstp == 0)
|
#define gcrunning(g) ((g)->gcstp == 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -261,6 +261,34 @@ u2 = setmetatable({}, {__gc = function () error("ZYX") end})
|
||||||
RUN('lua -W %s 2> %s', prog, out)
|
RUN('lua -W %s 2> %s', prog, out)
|
||||||
checkprogout("ZYX)\nXYZ)\n")
|
checkprogout("ZYX)\nXYZ)\n")
|
||||||
|
|
||||||
|
-- bug since 5.2: finalizer called when closing a state could
|
||||||
|
-- subvert finalization order
|
||||||
|
prepfile[[
|
||||||
|
-- should be called last
|
||||||
|
print("creating 1")
|
||||||
|
setmetatable({}, {__gc = function () print(1) end})
|
||||||
|
|
||||||
|
print("creating 2")
|
||||||
|
setmetatable({}, {__gc = function ()
|
||||||
|
print("2")
|
||||||
|
print("creating 3")
|
||||||
|
-- this finalizer should not be called, as object will be
|
||||||
|
-- created after 'lua_close' has been called
|
||||||
|
setmetatable({}, {__gc = function () print(3) end})
|
||||||
|
print(collectgarbage()) -- cannot call collector here
|
||||||
|
os.exit(0, true)
|
||||||
|
end})
|
||||||
|
]]
|
||||||
|
RUN('lua -W %s > %s', prog, out)
|
||||||
|
checkout[[
|
||||||
|
creating 1
|
||||||
|
creating 2
|
||||||
|
2
|
||||||
|
creating 3
|
||||||
|
nil
|
||||||
|
1
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
-- test many arguments
|
-- test many arguments
|
||||||
prepfile[[print(({...})[30])]]
|
prepfile[[print(({...})[30])]]
|
||||||
|
|
Loading…
Reference in New Issue