From 69dd9461e5aeb98fe9bbc71f1e81859d03ec8a34 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 28 Feb 2003 16:45:15 -0300 Subject: [PATCH] bug: GC metamethod calls could mess C/Lua stack syncronization --- bugs | 5 +++++ ldo.c | 18 +++++++++++------- lgc.h | 6 +++--- lstate.c | 11 ++++++++--- lvm.c | 23 +++++++++++++++++------ 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/bugs b/bugs index d87a158c..e39ae780 100644 --- a/bugs +++ b/bugs @@ -324,3 +324,8 @@ Thu Jan 23 11:29:06 UTC 2003 >> protected (by Benoit Germain; since 5.0a) +** ldo.c (and others) +Fri Feb 28 14:20:33 EST 2003 +>> GC metamethod calls could mess C/Lua stack syncronization +(by Roberto; since 5.0b) + diff --git a/ldo.c b/ldo.c index a285d6e1..985ab6e3 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.214 2003/02/27 11:52:30 roberto Exp roberto $ +** $Id: ldo.c,v 1.215 2003/02/28 15:42:08 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -292,7 +292,6 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { while (wanted-- > 0) setnilvalue(res++); L->top = res; - luaC_checkGC(L); } @@ -304,9 +303,10 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { */ void luaD_call (lua_State *L, StkId func, int nResults) { StkId firstResult; + lua_assert(!(L->ci->state & CI_CALLING)); if (++L->nCcalls >= LUA_MAXCCALLS) { if (L->nCcalls == LUA_MAXCCALLS) - luaG_runerror(L, "stack overflow"); + luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } @@ -315,6 +315,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { firstResult = luaV_execute(L); /* call it */ luaD_poscall(L, nResults, firstResult); L->nCcalls--; + luaC_checkGC(L); } @@ -428,10 +429,13 @@ struct SParser { /* data to `f_parser' */ }; static void f_parser (lua_State *L, void *ud) { - struct SParser *p = cast(struct SParser *, ud); - Proto *tf = p->bin ? luaU_undump(L, p->z, &p->buff) : - luaY_parser(L, p->z, &p->buff); - Closure *cl = luaF_newLclosure(L, 0, gt(L)); + struct SParser *p; + Proto *tf; + Closure *cl; + luaC_checkGC(L); + p = cast(struct SParser *, ud); + tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff); + cl = luaF_newLclosure(L, 0, gt(L)); cl->l.p = tf; setclvalue(L->top, cl); incr_top(L); diff --git a/lgc.h b/lgc.h index 78adf69a..8e3a3257 100644 --- a/lgc.h +++ b/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 1.17 2002/11/25 12:38:47 roberto Exp roberto $ +** $Id: lgc.h,v 1.18 2003/02/10 17:32:50 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -11,8 +11,8 @@ #include "lobject.h" -#define luaC_checkGC(L) if (G(L)->nblocks >= G(L)->GCthreshold) \ - luaC_collectgarbage(L) +#define luaC_checkGC(L) { lua_assert(!(L->ci->state & CI_CALLING)); \ + if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); } void luaC_separateudata (lua_State *L); diff --git a/lstate.c b/lstate.c index c35da871..150eb14d 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.119 2003/02/10 17:32:50 roberto Exp roberto $ +** $Id: lstate.c,v 1.120 2003/02/13 16:07:57 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -206,9 +206,14 @@ static void callallgcTM (lua_State *L, void *ud) { LUA_API void lua_close (lua_State *L) { lua_lock(L); L = G(L)->mainthread; /* only the main thread can be closed */ + luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L); /* separate udata that have GC metamethods */ - /* repeat until no more errors */ - while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0) /* skip */; + L->errfunc = 0; /* no error function during GC metamethods */ + do { /* repeat until no more errors */ + L->ci = L->base_ci; + L->base = L->top = L->ci->base; + L->nCcalls = 0; + } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); close_state(L); } diff --git a/lvm.c b/lvm.c index f999fae4..1a3054f8 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.277 2003/02/27 11:52:30 roberto Exp roberto $ +** $Id: lvm.c,v 1.278 2003/02/27 12:33:07 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -393,15 +393,21 @@ static void Arith (lua_State *L, StkId ra, #define dojump(pc, i) ((pc) += (i)) +unsigned int count = 0; + StkId luaV_execute (lua_State *L) { LClosure *cl; TObject *k; const Instruction *pc; +unsigned int ii, ic, ir, io; +ii = count; callentry: /* entry point when calling new functions */ +ic = count; L->ci->u.l.pc = &pc; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ +ir = count; lua_assert(L->ci->state == CI_SAVEDPC || L->ci->state == (CI_SAVEDPC | CI_CALLING)); L->ci->state = CI_HASFRAME; /* activate frame */ @@ -412,6 +418,7 @@ StkId luaV_execute (lua_State *L) { for (;;) { const Instruction i = *pc++; StkId base, ra; +count++; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L); @@ -658,20 +665,24 @@ StkId luaV_execute (lua_State *L) { break; } case OP_RETURN: { - CallInfo *ci = L->ci - 1; + CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); +io = count; if (b != 0) L->top = ra+b-1; lua_assert(L->ci->state & CI_HASFRAME); if (L->openupval) luaF_close(L, base); L->ci->state = CI_SAVEDPC; /* deactivate current function */ L->ci->u.l.savedpc = pc; /* previous function was running `here'? */ - if (!(ci->state & CI_CALLING)) + if (!(ci->state & CI_CALLING)) { + lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); return ra; /* no: return */ - else { /* yes: continue its execution (go through) */ + } + else { /* yes: continue its execution */ int nresults; - lua_assert(ttisfunction(ci->base - 1)); - lua_assert(ci->state & CI_SAVEDPC); + lua_assert(ci->u.l.pc == &pc && + ttisfunction(ci->base - 1) && + (ci->state & CI_SAVEDPC)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra);