diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-16 14:13:22 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-16 14:13:22 -0300 |
| commit | 298f383ffcc30d0799fbca0293175f647fe6bccf (patch) | |
| tree | b96f7572dd4e185007d20436db45c505976c3122 | |
| parent | 758c1ef445ab27d89bace746111add04083a8e20 (diff) | |
| download | lua-298f383ffcc30d0799fbca0293175f647fe6bccf.tar.gz lua-298f383ffcc30d0799fbca0293175f647fe6bccf.tar.bz2 lua-298f383ffcc30d0799fbca0293175f647fe6bccf.zip | |
Avoid setting the stack top below upvalues to be closed
When leaving a scope, the new stack top should be set only after
closing any upvalue, to avoid manipulating values in an "invalid"
part of the stack.
| -rw-r--r-- | lapi.c | 15 | ||||
| -rw-r--r-- | lfunc.c | 1 | ||||
| -rw-r--r-- | lvm.c | 6 |
3 files changed, 13 insertions, 9 deletions
| @@ -171,19 +171,20 @@ LUA_API int lua_gettop (lua_State *L) { | |||
| 171 | 171 | ||
| 172 | LUA_API void lua_settop (lua_State *L, int idx) { | 172 | LUA_API void lua_settop (lua_State *L, int idx) { |
| 173 | StkId func = L->ci->func; | 173 | StkId func = L->ci->func; |
| 174 | int diff; /* difference for new top */ | ||
| 174 | lua_lock(L); | 175 | lua_lock(L); |
| 175 | if (idx >= 0) { | 176 | if (idx >= 0) { |
| 176 | StkId newtop = (func + 1) + idx; | 177 | api_check(L, idx <= L->ci->top - (func + 1), "new top too large"); |
| 177 | api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); | 178 | diff = (func + 1) + idx - L->top; |
| 178 | while (L->top < newtop) | 179 | for (; diff > 0; diff--) |
| 179 | setnilvalue(s2v(L->top++)); | 180 | setnilvalue(s2v(L->top++)); /* clear new slots */ |
| 180 | L->top = newtop; | ||
| 181 | } | 181 | } |
| 182 | else { | 182 | else { |
| 183 | api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); | 183 | api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); |
| 184 | L->top += idx+1; /* 'subtract' index (index is negative) */ | 184 | diff = idx + 1; /* will "subtract" index (as it is negative) */ |
| 185 | } | 185 | } |
| 186 | luaF_close(L, L->top, LUA_OK); | 186 | luaF_close(L, L->top + diff, LUA_OK); |
| 187 | L->top += diff; /* correct top only after closing any upvalue */ | ||
| 187 | lua_unlock(L); | 188 | lua_unlock(L); |
| 188 | } | 189 | } |
| 189 | 190 | ||
| @@ -202,6 +202,7 @@ int luaF_close (lua_State *L, StkId level, int status) { | |||
| 202 | while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { | 202 | while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { |
| 203 | StkId upl = uplevel(uv); | 203 | StkId upl = uplevel(uv); |
| 204 | TValue *slot = &uv->u.value; /* new position for value */ | 204 | TValue *slot = &uv->u.value; /* new position for value */ |
| 205 | lua_assert(upl < L->top); | ||
| 205 | luaF_unlinkupval(uv); | 206 | luaF_unlinkupval(uv); |
| 206 | setobj(L, slot, uv->v); /* move value to upvalue slot */ | 207 | setobj(L, slot, uv->v); /* move value to upvalue slot */ |
| 207 | uv->v = slot; /* now current value lives here */ | 208 | uv->v = slot; /* now current value lives here */ |
| @@ -1601,15 +1601,17 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1601 | int n = GETARG_B(i) - 1; /* number of results */ | 1601 | int n = GETARG_B(i) - 1; /* number of results */ |
| 1602 | if (n < 0) /* not fixed? */ | 1602 | if (n < 0) /* not fixed? */ |
| 1603 | n = cast_int(L->top - ra); /* get what is available */ | 1603 | n = cast_int(L->top - ra); /* get what is available */ |
| 1604 | else | ||
| 1605 | L->top = ra + n; /* set call for 'luaD_poscall' */ | ||
| 1606 | savepc(ci); | 1604 | savepc(ci); |
| 1607 | if (TESTARG_k(i)) { | 1605 | if (TESTARG_k(i)) { |
| 1608 | int nparams1 = GETARG_C(i); | 1606 | int nparams1 = GETARG_C(i); |
| 1607 | if (L->top < ci->top) | ||
| 1608 | L->top = ci->top; | ||
| 1609 | luaF_close(L, base, LUA_OK); /* there may be open upvalues */ | 1609 | luaF_close(L, base, LUA_OK); /* there may be open upvalues */ |
| 1610 | updatestack(ci); | ||
| 1610 | if (nparams1) /* vararg function? */ | 1611 | if (nparams1) /* vararg function? */ |
| 1611 | ci->func -= ci->u.l.nextraargs + nparams1; | 1612 | ci->func -= ci->u.l.nextraargs + nparams1; |
| 1612 | } | 1613 | } |
| 1614 | L->top = ra + n; /* set call for 'luaD_poscall' */ | ||
| 1613 | luaD_poscall(L, ci, n); | 1615 | luaD_poscall(L, ci, n); |
| 1614 | return; | 1616 | return; |
| 1615 | } | 1617 | } |
