From 47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 7 Apr 2021 14:59:26 -0300 Subject: [PATCH] Bug: tbc variables in "for" loops don't avoid tail calls --- lparser.c | 21 +++++++++++++++------ testes/locals.lua | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/lparser.c b/lparser.c index 284ef1f0c..df9473c27 100644 --- a/src/lparser.c +++ b/src/lparser.c @@ -416,6 +416,17 @@ static void markupval (FuncState *fs, int level) { } +/* +** Mark that current block has a to-be-closed variable. +*/ +static void marktobeclosed (FuncState *fs) { + BlockCnt *bl = fs->bl; + bl->upval = 1; + bl->insidetbc = 1; + fs->needclose = 1; +} + + /* ** Find a variable with the given name 'n'. If it is an upvalue, add ** this upvalue into all intermediate functions. If it is a global, set @@ -1599,7 +1610,7 @@ static void forlist (LexState *ls, TString *indexname) { line = ls->linenumber; adjust_assign(ls, 4, explist(ls, &e), &e); adjustlocalvars(ls, 4); /* control variables */ - markupval(fs, fs->nactvar); /* last control var. must be closed */ + marktobeclosed(fs); /* last control var. must be closed */ luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 4, 1); } @@ -1703,11 +1714,9 @@ static int getlocalattribute (LexState *ls) { } -static void checktoclose (LexState *ls, int level) { +static void checktoclose (FuncState *fs, int level) { if (level != -1) { /* is there a to-be-closed variable? */ - FuncState *fs = ls->fs; - markupval(fs, level + 1); - fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ + marktobeclosed(fs); luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); } } @@ -1751,7 +1760,7 @@ static void localstat (LexState *ls) { adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } - checktoclose(ls, toclose); + checktoclose(fs, toclose); } From d205f3a4847bc8b835fda91f51ba1cf45b796baf Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Sat, 10 Apr 2021 10:19:21 -0300 Subject: [PATCH] Bug: Lua source should not use C99 comments ("//") --- lvm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lvm.c b/lvm.c index c9729bcca..16e01d683 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -1156,8 +1156,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { Instruction i; /* instruction being executed */ StkId ra; /* instruction's A register */ vmfetch(); -// low-level line tracing for debugging Lua -// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); + #if 0 + /* low-level line tracing for debugging Lua */ + printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); + #endif lua_assert(base == ci->func + 1); lua_assert(base <= L->top && L->top < L->stack_last); /* invalidate top for instructions not expecting it */ From 681297187ec45268e872b26753c441586c12bdd8 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 16 Apr 2021 15:41:44 -0300 Subject: [PATCH] Bug: yielding in '__close' mess up number of returns Yielding in a __close metamethod called when returning vararg results changes the top and so messes up the number of returned values. --- lstate.h | 2 +- lvm.c | 12 +++++++++- testes/locals.lua | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/lstate.h b/lstate.h index c1283bb6b..44cf939cb 100644 --- a/src/lstate.h +++ b/src/lstate.h @@ -165,7 +165,7 @@ typedef struct stringtable { ** - field 'nyield' is used only while a function is "doing" an ** yield (from the yield until the next resume); ** - field 'nres' is used only while closing tbc variables when -** returning from a C function; +** returning from a function; ** - field 'transferinfo' is used only during call/returnhooks, ** before the function starts or after it ends. */ diff --git a/lvm.c b/lvm.c index 16e01d683..e4b1903e7 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -847,10 +847,19 @@ void luaV_finishOp (lua_State *L) { luaV_concat(L, total); /* concat them (may yield again) */ break; } - case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */ + case OP_CLOSE: { /* yielded closing variables */ ci->u.l.savedpc--; /* repeat instruction to close other vars. */ break; } + case OP_RETURN: { /* yielded closing variables */ + StkId ra = base + GETARG_A(inst); + /* adjust top to signal correct number of returns, in case the + return is "up to top" ('isIT') */ + L->top = ra + ci->u2.nres; + /* repeat instruction to close other vars. and complete the return */ + ci->u.l.savedpc--; + break; + } default: { /* only these other opcodes can yield */ lua_assert(op == OP_TFORCALL || op == OP_CALL || @@ -1672,6 +1681,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { n = cast_int(L->top - ra); /* get what is available */ savepc(ci); if (TESTARG_k(i)) { /* may there be open upvalues? */ + ci->u2.nres = n; /* save number of returns */ if (L->top < ci->top) L->top = ci->top; luaF_close(L, base, CLOSEKTOP, 1);