diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-25 12:50:20 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-25 12:50:20 -0300 |
commit | 41c800b352149e037bdebd5f20d2f25ed2a0e2a5 (patch) | |
tree | 740a459fd69d687dfe200fc91762208079e0c25b /lparser.c | |
parent | 0a9aca56caa925c42aaa683b43560357ab736ea4 (diff) | |
download | lua-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.c | 15 |
1 files changed, 7 insertions, 8 deletions
@@ -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 | } |