mirror of
https://github.com/lua/lua
synced 2024-11-22 21:01:26 +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
|
>> 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
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
|
** 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
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
|
** 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);
|
||||||
|
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
|
** 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
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
|
** 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);
|
||||||
|
Loading…
Reference in New Issue
Block a user