diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-05-25 17:41:39 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-05-25 17:41:39 -0300 |
| commit | 196bb94d66e727e0aec053a0276c3ad701500762 (patch) | |
| tree | a7639f32207179b5bd5e1ce04dd35972e1b2e148 | |
| parent | 603b2c64add5fbf4b7343525cf109af0c7077695 (diff) | |
| download | lua-196bb94d66e727e0aec053a0276c3ad701500762.tar.gz lua-196bb94d66e727e0aec053a0276c3ad701500762.tar.bz2 lua-196bb94d66e727e0aec053a0276c3ad701500762.zip | |
Bug: 'lua_settop' may use an invalid pointer to stack
| -rw-r--r-- | lapi.c | 5 | ||||
| -rw-r--r-- | ldo.c | 12 | ||||
| -rw-r--r-- | lfunc.c | 5 | ||||
| -rw-r--r-- | lfunc.h | 2 | ||||
| -rw-r--r-- | testes/locals.lua | 22 |
5 files changed, 34 insertions, 12 deletions
| @@ -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 | } |
| @@ -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 */ |
| @@ -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 | */ |
| 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) { |
| 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 | ||
| @@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); | |||
| 54 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); | 54 | LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); |
| 55 | LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); | 55 | LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); |
| 56 | LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); | 56 | 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); |
| 58 | LUAI_FUNC void luaF_unlinkupval (UpVal *uv); | 58 | LUAI_FUNC void luaF_unlinkupval (UpVal *uv); |
| 59 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); | 59 | LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); |
| 60 | LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, | 60 | LUAI_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 | ||
| 593 | if rawget(_G, "T") then | 593 | if 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) |
