diff --git a/lapi.h b/lapi.h index 5a4206f1..f48d14fd 100644 --- a/lapi.h +++ b/lapi.h @@ -11,12 +11,22 @@ #include "llimits.h" #include "lstate.h" + +/* Increments 'L->top', checking for stack overflows */ #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ "stack overflow");} + +/* +** If a call returns too many multiple returns, the callee may not have +** stack space to accomodate all results. In this case, this macro +** increases its stack space ('L->ci->top'). +*/ #define adjustresults(L,nres) \ { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } + +/* Ensure the stack has at least 'n' elements */ #define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ "not enough elements in the stack") diff --git a/lparser.c b/lparser.c index b70c609e..7447222b 100644 --- a/lparser.c +++ b/lparser.c @@ -694,9 +694,10 @@ static Proto *addprototype (LexState *ls) { /* ** codes instruction to create new closure in parent function. -** The OP_CLOSURE instruction must use the last available register, +** The OP_CLOSURE instruction uses the last available register, ** so that, if it invokes the GC, the GC knows which registers ** are in use at that time. + */ static void codeclosure (LexState *ls, expdesc *v) { FuncState *fs = ls->fs->prev; diff --git a/lvm.c b/lvm.c index d9bd0ab3..26477c2c 100644 --- a/lvm.c +++ b/lvm.c @@ -1258,7 +1258,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { if (TESTARG_k(i)) c += GETARG_Ax(*pc) * (MAXARG_C + 1); pc++; /* skip extra argument */ - L->top = ci->top; /* correct top in case of GC */ + L->top = ra + 1; /* correct top in case of emergency GC */ t = luaH_new(L); /* memory allocation */ sethvalue2s(L, ra, t); if (b != 0 || c != 0) @@ -1478,7 +1478,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_CLOSE) { - L->top = ra + 1; /* everything is free after this slot */ Protect(luaF_close(L, ra, LUA_OK)); vmbreak; } @@ -1755,7 +1754,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { /* push function, state, and control variable */ memcpy(ra + 4, ra, 3 * sizeof(*ra)); L->top = ra + 4 + 3; - Protect(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ + ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ updatestack(ci); /* stack may have changed */ i = *(pc++); /* go to next instruction */ lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); @@ -1776,7 +1775,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { if (n == 0) n = cast_int(L->top - ra) - 1; /* get up to the top */ else - L->top = ci->top; /* correct top in case of GC */ + L->top = ci->top; /* correct top in case of emergency GC */ last += n; if (TESTARG_k(i)) { last += GETARG_Ax(*pc) * (MAXARG_C + 1); diff --git a/testes/nextvar.lua b/testes/nextvar.lua index a7fe625e..9d919631 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua @@ -671,7 +671,8 @@ collectgarbage() local function f (n, p) local t = {}; for i=1,p do t[i] = i*10 end - return function (_,n) + return function (_, n, ...) + assert(select("#", ...) == 0) -- no extra arguments if n > 0 then n = n-1 return n, table.unpack(t)