aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-05-25 17:41:39 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-05-25 17:41:39 -0300
commit196bb94d66e727e0aec053a0276c3ad701500762 (patch)
treea7639f32207179b5bd5e1ce04dd35972e1b2e148
parent603b2c64add5fbf4b7343525cf109af0c7077695 (diff)
downloadlua-196bb94d66e727e0aec053a0276c3ad701500762.tar.gz
lua-196bb94d66e727e0aec053a0276c3ad701500762.tar.bz2
lua-196bb94d66e727e0aec053a0276c3ad701500762.zip
Bug: 'lua_settop' may use an invalid pointer to stack
-rw-r--r--lapi.c5
-rw-r--r--ldo.c12
-rw-r--r--lfunc.c5
-rw-r--r--lfunc.h2
-rw-r--r--testes/locals.lua22
5 files changed, 34 insertions, 12 deletions
diff --git a/lapi.c b/lapi.c
index 352a385a..5833c7b0 100644
--- a/lapi.c
+++ b/lapi.c
@@ -197,7 +197,7 @@ LUA_API void lua_settop (lua_State *L, int idx) {
197 newtop = L->top + diff; 197 newtop = L->top + diff;
198 if (diff < 0 && L->tbclist >= newtop) { 198 if (diff < 0 && L->tbclist >= newtop) {
199 lua_assert(hastocloseCfunc(ci->nresults)); 199 lua_assert(hastocloseCfunc(ci->nresults));
200 luaF_close(L, newtop, CLOSEKTOP, 0); 200 newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
201 } 201 }
202 L->top = newtop; /* correct top only after closing any upvalue */ 202 L->top = newtop; /* correct top only after closing any upvalue */
203 lua_unlock(L); 203 lua_unlock(L);
@@ -210,8 +210,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
210 level = index2stack(L, idx); 210 level = index2stack(L, idx);
211 api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level, 211 api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
212 "no variable to close at given level"); 212 "no variable to close at given level");
213 luaF_close(L, level, CLOSEKTOP, 0); 213 level = luaF_close(L, level, CLOSEKTOP, 0);
214 level = index2stack(L, idx); /* stack may be moved */
215 setnilvalue(s2v(level)); 214 setnilvalue(s2v(level));
216 lua_unlock(L); 215 lua_unlock(L);
217} 216}
diff --git a/ldo.c b/ldo.c
index 5aa6d59d..13498905 100644
--- a/ldo.c
+++ b/ldo.c
@@ -430,14 +430,15 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
430 break; 430 break;
431 default: /* two/more results and/or to-be-closed variables */ 431 default: /* two/more results and/or to-be-closed variables */
432 if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ 432 if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
433 ptrdiff_t savedres = savestack(L, res);
434 L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ 433 L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
435 L->ci->u2.nres = nres; 434 L->ci->u2.nres = nres;
436 luaF_close(L, res, CLOSEKTOP, 1); 435 res = luaF_close(L, res, CLOSEKTOP, 1);
437 L->ci->callstatus &= ~CIST_CLSRET; 436 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);
439 rethook(L, L->ci, nres); 439 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 }
441 wanted = decodeNresults(wanted); 442 wanted = decodeNresults(wanted);
442 if (wanted == LUA_MULTRET) 443 if (wanted == LUA_MULTRET)
443 wanted = nres; /* we want all results */ 444 wanted = nres; /* we want all results */
@@ -654,8 +655,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
654 else { /* error */ 655 else { /* error */
655 StkId func = restorestack(L, ci->u2.funcidx); 656 StkId func = restorestack(L, ci->u2.funcidx);
656 L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ 657 L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
657 luaF_close(L, func, status, 1); /* can yield or raise an error */ 658 func = luaF_close(L, func, status, 1); /* can yield or raise an error */
658 func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
659 luaD_seterrorobj(L, status, func); 659 luaD_seterrorobj(L, status, func);
660 luaD_shrinkstack(L); /* restore stack size in case of overflow */ 660 luaD_shrinkstack(L); /* restore stack size in case of overflow */
661 setcistrecst(ci, LUA_OK); /* clear original status */ 661 setcistrecst(ci, LUA_OK); /* clear original status */
diff --git a/lfunc.c b/lfunc.c
index f5889a21..3ed65de2 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -223,9 +223,9 @@ static void poptbclist (lua_State *L) {
223 223
224/* 224/*
225** Close all upvalues and to-be-closed variables up to the given stack 225** Close all upvalues and to-be-closed variables up to the given stack
226** level. 226** level. Return restored 'level'.
227*/ 227*/
228void luaF_close (lua_State *L, StkId level, int status, int yy) { 228StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
229 ptrdiff_t levelrel = savestack(L, level); 229 ptrdiff_t levelrel = savestack(L, level);
230 luaF_closeupval(L, level); /* first, close the upvalues */ 230 luaF_closeupval(L, level); /* first, close the upvalues */
231 while (L->tbclist >= level) { /* traverse tbc's down to that level */ 231 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) {
234 prepcallclosemth(L, tbc, status, yy); /* close variable */ 234 prepcallclosemth(L, tbc, status, yy); /* close variable */
235 level = restorestack(L, levelrel); 235 level = restorestack(L, levelrel);
236 } 236 }
237 return level;
237} 238}
238 239
239 240
diff --git a/lfunc.h b/lfunc.h
index dc1cebcc..3d296971 100644
--- a/lfunc.h
+++ b/lfunc.h
@@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
54LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); 54LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
55LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); 55LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
56LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); 56LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
57LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); 57LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
58LUAI_FUNC void luaF_unlinkupval (UpVal *uv); 58LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
59LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); 59LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
60LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, 60LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
diff --git a/testes/locals.lua b/testes/locals.lua
index 62a88df5..ddb75054 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -592,6 +592,28 @@ end
592 592
593if rawget(_G, "T") then 593if rawget(_G, "T") then
594 594
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
595 -- memory error inside closing function 617 -- memory error inside closing function
596 local function foo () 618 local function foo ()
597 local y <close> = func2close(function () T.alloccount() end) 619 local y <close> = func2close(function () T.alloccount() end)