From 41c800b352149e037bdebd5f20d2f25ed2a0e2a5 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 25 Oct 2018 12:50:20 -0300 Subject: 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. --- lparser.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'lparser.c') 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) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; - luaK_ret(fs, 0, 0); /* final return */ + luaK_ret(fs, fs->nactvar, 0); /* final return */ leaveblock(fs); lua_assert(fs->bl == NULL); luaK_finish(fs); @@ -1602,9 +1602,10 @@ static void retstat (LexState *ls) { /* stat -> RETURN [explist] [';'] */ FuncState *fs = ls->fs; expdesc e; - int first, nret; /* registers with returned values */ + int nret; /* number of values being returned */ + int first = fs->nactvar; /* first slot to be returned */ if (block_follow(ls, 1) || ls->t.token == ';') - first = nret = 0; /* return no values */ + nret = 0; /* return no values */ else { nret = explist(ls, &e); /* optional return values */ if (hasmultret(e.k)) { @@ -1613,15 +1614,13 @@ static void retstat (LexState *ls) { SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); } - first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ - first = luaK_exp2anyreg(fs, &e); - else { - luaK_exp2nextreg(fs, &e); /* values must go to the stack */ - first = fs->nactvar; /* return all active values */ + first = luaK_exp2anyreg(fs, &e); /* can use original slot */ + else { /* values must go to the top of the stack */ + luaK_exp2nextreg(fs, &e); lua_assert(nret == fs->freereg - first); } } -- cgit v1.2.3-55-g6feb