Skip to content

Commit 196bb94

Browse files
committedMay 25, 2022
Bug: 'lua_settop' may use an invalid pointer to stack
1 parent 603b2c6 commit 196bb94

File tree

5 files changed

+34
-12
lines changed

5 files changed

+34
-12
lines changed
 

‎lapi.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ LUA_API void lua_settop (lua_State *L, int idx) {
197197
newtop = L->top + diff;
198198
if (diff < 0 && L->tbclist >= newtop) {
199199
lua_assert(hastocloseCfunc(ci->nresults));
200-
luaF_close(L, newtop, CLOSEKTOP, 0);
200+
newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
201201
}
202202
L->top = newtop; /* correct top only after closing any upvalue */
203203
lua_unlock(L);
@@ -210,8 +210,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
210210
level = index2stack(L, idx);
211211
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
212212
"no variable to close at given level");
213-
luaF_close(L, level, CLOSEKTOP, 0);
214-
level = index2stack(L, idx); /* stack may be moved */
213+
level = luaF_close(L, level, CLOSEKTOP, 0);
215214
setnilvalue(s2v(level));
216215
lua_unlock(L);
217216
}

‎ldo.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -430,14 +430,15 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
430430
break;
431431
default: /* two/more results and/or to-be-closed variables */
432432
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
433-
ptrdiff_t savedres = savestack(L, res);
434433
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
435434
L->ci->u2.nres = nres;
436-
luaF_close(L, res, CLOSEKTOP, 1);
435+
res = luaF_close(L, res, CLOSEKTOP, 1);
437436
L->ci->callstatus &= ~CIST_CLSRET;
438-
if (L->hookmask) /* if needed, call hook after '__close's */
437+
if (L->hookmask) { /* if needed, call hook after '__close's */
438+
ptrdiff_t savedres = savestack(L, res);
439439
rethook(L, L->ci, nres);
440-
res = restorestack(L, savedres); /* close and hook can move stack */
440+
res = restorestack(L, savedres); /* hook can move stack */
441+
}
441442
wanted = decodeNresults(wanted);
442443
if (wanted == LUA_MULTRET)
443444
wanted = nres; /* we want all results */
@@ -654,8 +655,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
654655
else { /* error */
655656
StkId func = restorestack(L, ci->u2.funcidx);
656657
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
657-
luaF_close(L, func, status, 1); /* can yield or raise an error */
658-
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
658+
func = luaF_close(L, func, status, 1); /* can yield or raise an error */
659659
luaD_seterrorobj(L, status, func);
660660
luaD_shrinkstack(L); /* restore stack size in case of overflow */
661661
setcistrecst(ci, LUA_OK); /* clear original status */

‎lfunc.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,9 @@ static void poptbclist (lua_State *L) {
223223

224224
/*
225225
** Close all upvalues and to-be-closed variables up to the given stack
226-
** level.
226+
** level. Return restored 'level'.
227227
*/
228-
void luaF_close (lua_State *L, StkId level, int status, int yy) {
228+
StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
229229
ptrdiff_t levelrel = savestack(L, level);
230230
luaF_closeupval(L, level); /* first, close the upvalues */
231231
while (L->tbclist >= level) { /* traverse tbc's down to that level */
@@ -234,6 +234,7 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) {
234234
prepcallclosemth(L, tbc, status, yy); /* close variable */
235235
level = restorestack(L, levelrel);
236236
}
237+
return level;
237238
}
238239

239240

‎lfunc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
5454
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
5555
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
5656
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
57-
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
57+
LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
5858
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
5959
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
6060
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

‎testes/locals.lua

+22
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,28 @@ end
592592

593593
if rawget(_G, "T") then
594594

595+
do
596+
-- bug in 5.4.3
597+
-- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
598+
599+
-- reduce stack size
600+
collectgarbage(); collectgarbage(); collectgarbage()
601+
602+
-- force a stack reallocation
603+
local function loop (n)
604+
if n < 400 then loop(n + 1) end
605+
end
606+
607+
-- close metamethod will reallocate the stack
608+
local o = setmetatable({}, {__close = function () loop(0) end})
609+
610+
local script = [[toclose 2; settop 1; return 1]]
611+
612+
assert(T.testC(script, o) == script)
613+
614+
end
615+
616+
595617
-- memory error inside closing function
596618
local function foo ()
597619
local y <close> = func2close(function () T.alloccount() end)

0 commit comments

Comments
 (0)
Please sign in to comment.