aboutsummaryrefslogtreecommitdiff
path: root/lparser.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-10-25 12:50:20 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-10-25 12:50:20 -0300
commit41c800b352149e037bdebd5f20d2f25ed2a0e2a5 (patch)
tree740a459fd69d687dfe200fc91762208079e0c25b /lparser.c
parent0a9aca56caa925c42aaa683b43560357ab736ea4 (diff)
downloadlua-41c800b352149e037bdebd5f20d2f25ed2a0e2a5.tar.gz
lua-41c800b352149e037bdebd5f20d2f25ed2a0e2a5.tar.bz2
lua-41c800b352149e037bdebd5f20d2f25ed2a0e2a5.zip
Closing methods should not interfere with returning values
A closing method cannot be called in its own stack slot, as there may be returning values in the stack after that slot, and the call would corrupt those values. Instead, the closing method must be copied to the top of the stack to be called. Moreover, even when a function returns no value, its return istruction still has to have its position (which will set the stack top) after the local variables, otherwise a closing method might corrupt another not-yet-called closing method.
Diffstat (limited to 'lparser.c')
-rw-r--r--lparser.c15
1 files changed, 7 insertions, 8 deletions
diff --git a/lparser.c b/lparser.c
index 6b14b800..c0c40eae 100644
--- a/lparser.c
+++ b/lparser.c
@@ -561,7 +561,7 @@ static void close_func (LexState *ls) {
561 lua_State *L = ls->L; 561 lua_State *L = ls->L;
562 FuncState *fs = ls->fs; 562 FuncState *fs = ls->fs;
563 Proto *f = fs->f; 563 Proto *f = fs->f;
564 luaK_ret(fs, 0, 0); /* final return */ 564 luaK_ret(fs, fs->nactvar, 0); /* final return */
565 leaveblock(fs); 565 leaveblock(fs);
566 lua_assert(fs->bl == NULL); 566 lua_assert(fs->bl == NULL);
567 luaK_finish(fs); 567 luaK_finish(fs);
@@ -1602,9 +1602,10 @@ static void retstat (LexState *ls) {
1602 /* stat -> RETURN [explist] [';'] */ 1602 /* stat -> RETURN [explist] [';'] */
1603 FuncState *fs = ls->fs; 1603 FuncState *fs = ls->fs;
1604 expdesc e; 1604 expdesc e;
1605 int first, nret; /* registers with returned values */ 1605 int nret; /* number of values being returned */
1606 int first = fs->nactvar; /* first slot to be returned */
1606 if (block_follow(ls, 1) || ls->t.token == ';') 1607 if (block_follow(ls, 1) || ls->t.token == ';')
1607 first = nret = 0; /* return no values */ 1608 nret = 0; /* return no values */
1608 else { 1609 else {
1609 nret = explist(ls, &e); /* optional return values */ 1610 nret = explist(ls, &e); /* optional return values */
1610 if (hasmultret(e.k)) { 1611 if (hasmultret(e.k)) {
@@ -1613,15 +1614,13 @@ static void retstat (LexState *ls) {
1613 SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); 1614 SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
1614 lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); 1615 lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
1615 } 1616 }
1616 first = fs->nactvar;
1617 nret = LUA_MULTRET; /* return all values */ 1617 nret = LUA_MULTRET; /* return all values */
1618 } 1618 }
1619 else { 1619 else {
1620 if (nret == 1) /* only one single value? */ 1620 if (nret == 1) /* only one single value? */
1621 first = luaK_exp2anyreg(fs, &e); 1621 first = luaK_exp2anyreg(fs, &e); /* can use original slot */
1622 else { 1622 else { /* values must go to the top of the stack */
1623 luaK_exp2nextreg(fs, &e); /* values must go to the stack */ 1623 luaK_exp2nextreg(fs, &e);
1624 first = fs->nactvar; /* return all active values */
1625 lua_assert(nret == fs->freereg - first); 1624 lua_assert(nret == fs->freereg - first);
1626 } 1625 }
1627 } 1626 }