bug: GC metamethod calls could mess C/Lua stack syncronization

This commit is contained in:
Roberto Ierusalimschy 2003-02-28 16:45:15 -03:00
parent 6b6bc532a4
commit 69dd9461e5
5 changed files with 44 additions and 19 deletions

5
bugs
View File

@ -324,3 +324,8 @@ Thu Jan 23 11:29:06 UTC 2003
>> protected >> protected
(by Benoit Germain; since 5.0a) (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)

18
ldo.c
View File

@ -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 ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -292,7 +292,6 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
while (wanted-- > 0) while (wanted-- > 0)
setnilvalue(res++); setnilvalue(res++);
L->top = 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) { void luaD_call (lua_State *L, StkId func, int nResults) {
StkId firstResult; StkId firstResult;
lua_assert(!(L->ci->state & CI_CALLING));
if (++L->nCcalls >= LUA_MAXCCALLS) { if (++L->nCcalls >= LUA_MAXCCALLS) {
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))) else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3)))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ 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 */ firstResult = luaV_execute(L); /* call it */
luaD_poscall(L, nResults, firstResult); luaD_poscall(L, nResults, firstResult);
L->nCcalls--; L->nCcalls--;
luaC_checkGC(L);
} }
@ -428,10 +429,13 @@ struct SParser { /* data to `f_parser' */
}; };
static void f_parser (lua_State *L, void *ud) { static void f_parser (lua_State *L, void *ud) {
struct SParser *p = cast(struct SParser *, ud); struct SParser *p;
Proto *tf = p->bin ? luaU_undump(L, p->z, &p->buff) : Proto *tf;
luaY_parser(L, p->z, &p->buff); Closure *cl;
Closure *cl = luaF_newLclosure(L, 0, gt(L)); 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; cl->l.p = tf;
setclvalue(L->top, cl); setclvalue(L->top, cl);
incr_top(L); incr_top(L);

6
lgc.h
View File

@ -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 ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -11,8 +11,8 @@
#include "lobject.h" #include "lobject.h"
#define luaC_checkGC(L) if (G(L)->nblocks >= G(L)->GCthreshold) \ #define luaC_checkGC(L) { lua_assert(!(L->ci->state & CI_CALLING)); \
luaC_collectgarbage(L) if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); }
void luaC_separateudata (lua_State *L); void luaC_separateudata (lua_State *L);

View File

@ -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 ** Global State
** See Copyright Notice in lua.h ** 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_API void lua_close (lua_State *L) {
lua_lock(L); lua_lock(L);
L = G(L)->mainthread; /* only the main thread can be closed */ 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 */ luaC_separateudata(L); /* separate udata that have GC metamethods */
/* repeat until no more errors */ L->errfunc = 0; /* no error function during GC metamethods */
while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0) /* skip */; 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); lua_assert(G(L)->tmudata == NULL);
close_state(L); close_state(L);
} }

23
lvm.c
View File

@ -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 ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -393,15 +393,21 @@ static void Arith (lua_State *L, StkId ra,
#define dojump(pc, i) ((pc) += (i)) #define dojump(pc, i) ((pc) += (i))
unsigned int count = 0;
StkId luaV_execute (lua_State *L) { StkId luaV_execute (lua_State *L) {
LClosure *cl; LClosure *cl;
TObject *k; TObject *k;
const Instruction *pc; const Instruction *pc;
unsigned int ii, ic, ir, io;
ii = count;
callentry: /* entry point when calling new functions */ callentry: /* entry point when calling new functions */
ic = count;
L->ci->u.l.pc = &pc; L->ci->u.l.pc = &pc;
if (L->hookmask & LUA_MASKCALL) if (L->hookmask & LUA_MASKCALL)
luaD_callhook(L, LUA_HOOKCALL, -1); luaD_callhook(L, LUA_HOOKCALL, -1);
retentry: /* entry point when returning to old functions */ retentry: /* entry point when returning to old functions */
ir = count;
lua_assert(L->ci->state == CI_SAVEDPC || lua_assert(L->ci->state == CI_SAVEDPC ||
L->ci->state == (CI_SAVEDPC | CI_CALLING)); L->ci->state == (CI_SAVEDPC | CI_CALLING));
L->ci->state = CI_HASFRAME; /* activate frame */ L->ci->state = CI_HASFRAME; /* activate frame */
@ -412,6 +418,7 @@ StkId luaV_execute (lua_State *L) {
for (;;) { for (;;) {
const Instruction i = *pc++; const Instruction i = *pc++;
StkId base, ra; StkId base, ra;
count++;
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
traceexec(L); traceexec(L);
@ -658,20 +665,24 @@ StkId luaV_execute (lua_State *L) {
break; break;
} }
case OP_RETURN: { case OP_RETURN: {
CallInfo *ci = L->ci - 1; CallInfo *ci = L->ci - 1; /* previous function frame */
int b = GETARG_B(i); int b = GETARG_B(i);
io = count;
if (b != 0) L->top = ra+b-1; if (b != 0) L->top = ra+b-1;
lua_assert(L->ci->state & CI_HASFRAME); lua_assert(L->ci->state & CI_HASFRAME);
if (L->openupval) luaF_close(L, base); if (L->openupval) luaF_close(L, base);
L->ci->state = CI_SAVEDPC; /* deactivate current function */ L->ci->state = CI_SAVEDPC; /* deactivate current function */
L->ci->u.l.savedpc = pc; L->ci->u.l.savedpc = pc;
/* previous function was running `here'? */ /* 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 */ return ra; /* no: return */
else { /* yes: continue its execution (go through) */ }
else { /* yes: continue its execution */
int nresults; int nresults;
lua_assert(ttisfunction(ci->base - 1)); lua_assert(ci->u.l.pc == &pc &&
lua_assert(ci->state & CI_SAVEDPC); ttisfunction(ci->base - 1) &&
(ci->state & CI_SAVEDPC));
lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL);
nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1;
luaD_poscall(L, nresults, ra); luaD_poscall(L, nresults, ra);