1
0
mirror of https://github.com/lua/lua.git synced 2025-01-28 06:03:00 +08:00

Fixed wrong trace of vararg functions

Trace of vararg functions was skipping an instruction when returning
from a call. (Bug introduced by commit 5d8ce05b3.)
This commit is contained in:
Roberto Ierusalimschy 2020-10-19 15:55:25 -03:00
parent f07de22576
commit e4a38eb0e8
2 changed files with 35 additions and 20 deletions

45
lvm.c
View File

@ -1092,15 +1092,11 @@ void luaV_finishOp (lua_State *L) {
#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci))
/* /*
** Protect code that will finish the loop (returns) or can only raise ** Protect code that can only raise errors. (That is, it cannnot change
** errors. (That is, it will not return to the interpreter main loop ** the stack or hooks.)
** after changing the stack or hooks.)
*/ */
#define halfProtect(exp) (savestate(L,ci), (exp)) #define halfProtect(exp) (savestate(L,ci), (exp))
/* idem, but without changing the stack */
#define halfProtectNT(exp) (savepc(L), (exp))
/* 'c' is the limit of live values in the stack */ /* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \ #define checkGC(L,c) \
{ luaC_condGC(L, (savepc(L), L->top = (c)), \ { luaC_condGC(L, (savepc(L), L->top = (c)), \
@ -1132,17 +1128,20 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
#if LUA_USE_JUMPTABLE #if LUA_USE_JUMPTABLE
#include "ljumptab.h" #include "ljumptab.h"
#endif #endif
execute: startfunc:
trap = L->hookmask; trap = L->hookmask;
returning: /* trap already set */
cl = clLvalue(s2v(ci->func)); cl = clLvalue(s2v(ci->func));
k = cl->p->k; k = cl->p->k;
pc = ci->u.l.savedpc; pc = ci->u.l.savedpc;
if (trap) { if (trap) {
if (cl->p->is_vararg) if (pc == cl->p->code) { /* first instruction (not resuming)? */
trap = 0; /* hooks will start after VARARGPREP instruction */ if (cl->p->is_vararg)
else if (pc == cl->p->code) /* first instruction (not resuming)? */ trap = 0; /* hooks will start after VARARGPREP instruction */
luaD_hookcall(L, ci); else /* check 'call' hook */
ci->u.l.trap = 1; /* there may be other hooks */ luaD_hookcall(L, ci);
}
ci->u.l.trap = 1; /* assume trap is on, for now */
} }
base = ci->func + 1; base = ci->func + 1;
/* main loop of interpreter */ /* main loop of interpreter */
@ -1615,10 +1614,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
savepc(L); /* in case of errors */ savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL) if ((newci = luaD_precall(L, ra, nresults)) == NULL)
updatetrap(ci); /* C call; nothing else to be done */ updatetrap(ci); /* C call; nothing else to be done */
else { /* Lua call: run function in this same invocation */ else { /* Lua call: run function in this same C frame */
ci = newci; ci = newci;
ci->callstatus = 0; /* call re-uses 'luaV_execute' */ ci->callstatus = 0; /* call re-uses 'luaV_execute' */
goto execute; goto startfunc;
} }
vmbreak; vmbreak;
} }
@ -1631,7 +1630,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
L->top = ra + b; L->top = ra + b;
else /* previous instruction set top */ else /* previous instruction set top */
b = cast_int(L->top - ra); b = cast_int(L->top - ra);
savepc(ci); /* some calls here can raise errors */ savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) { if (TESTARG_k(i)) {
/* close upvalues from current call; the compiler ensures /* close upvalues from current call; the compiler ensures
that there are no to-be-closed variables here, so this that there are no to-be-closed variables here, so this
@ -1650,11 +1649,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
updatestack(ci); /* stack may have been relocated */ updatestack(ci); /* stack may have been relocated */
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */ goto ret; /* caller returns after the tail call */
} }
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func -= delta; /* restore 'func' (if vararg) */
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
goto execute; /* execute the callee */ goto startfunc; /* execute the callee */
} }
vmcase(OP_RETURN) { vmcase(OP_RETURN) {
int n = GETARG_B(i) - 1; /* number of results */ int n = GETARG_B(i) - 1; /* number of results */
@ -1673,12 +1673,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
ci->func -= ci->u.l.nextraargs + nparams1; ci->func -= ci->u.l.nextraargs + nparams1;
L->top = ra + n; /* set call for 'luaD_poscall' */ L->top = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n); luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; goto ret;
} }
vmcase(OP_RETURN0) { vmcase(OP_RETURN0) {
if (L->hookmask) { if (L->hookmask) {
L->top = ra; L->top = ra;
halfProtectNT(luaD_poscall(L, ci, 0)); /* no hurry... */ savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1;
} }
else { /* do the 'poscall' here */ else { /* do the 'poscall' here */
int nres = ci->nresults; int nres = ci->nresults;
@ -1692,7 +1695,9 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmcase(OP_RETURN1) { vmcase(OP_RETURN1) {
if (L->hookmask) { if (L->hookmask) {
L->top = ra + 1; L->top = ra + 1;
halfProtectNT(luaD_poscall(L, ci, 1)); /* no hurry... */ savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1;
} }
else { /* do the 'poscall' here */ else { /* do the 'poscall' here */
int nres = ci->nresults; int nres = ci->nresults;
@ -1706,12 +1711,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
setnilvalue(s2v(L->top++)); setnilvalue(s2v(L->top++));
} }
} }
ret: ret: /* return from a Lua function */
if (ci->callstatus & CIST_FRESH) if (ci->callstatus & CIST_FRESH)
return; /* end this frame */ return; /* end this frame */
else { else {
ci = ci->previous; ci = ci->previous;
goto execute; /* continue running caller in this frame */ goto returning; /* continue running caller in this frame */
} }
} }
vmcase(OP_FORLOOP) { vmcase(OP_FORLOOP) {

View File

@ -119,6 +119,16 @@ else
end end
]], {2,3,4,7}) ]], {2,3,4,7})
test([[
local function foo()
end
foo()
A = 1
A = 2
A = 3
]], {2, 3, 2, 4, 5, 6})
test([[-- test([[--
if nil then if nil then
a=1 a=1