mirror of
https://github.com/lua/lua
synced 2024-11-26 06:39:41 +03:00
bug: GC metamethod calls could mess C/Lua stack syncronization
This commit is contained in:
parent
6b6bc532a4
commit
69dd9461e5
5
bugs
5
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)
|
||||
|
||||
|
18
ldo.c
18
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);
|
||||
|
6
lgc.h
6
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);
|
||||
|
11
lstate.c
11
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);
|
||||
}
|
||||
|
23
lvm.c
23
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);
|
||||
|
Loading…
Reference in New Issue
Block a user