diff options
| -rw-r--r-- | ldo.c | 54 |
1 files changed, 44 insertions, 10 deletions
| @@ -191,6 +191,16 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
| 191 | 191 | ||
| 192 | 192 | ||
| 193 | /* | 193 | /* |
| 194 | ** In ISO C, any pointer use after the pointer has been deallocated is | ||
| 195 | ** undefined behavior. So, before a stack reallocation, all pointers are | ||
| 196 | ** changed to offsets, and after the reallocation they are changed back | ||
| 197 | ** to pointers. As during the reallocation the pointers are invalid, the | ||
| 198 | ** reallocation cannot run emergency collections. | ||
| 199 | ** | ||
| 200 | */ | ||
| 201 | |||
| 202 | #if 1 | ||
| 203 | /* | ||
| 194 | ** Change all pointers to the stack into offsets. | 204 | ** Change all pointers to the stack into offsets. |
| 195 | */ | 205 | */ |
| 196 | static void relstack (lua_State *L) { | 206 | static void relstack (lua_State *L) { |
| @@ -210,9 +220,10 @@ static void relstack (lua_State *L) { | |||
| 210 | /* | 220 | /* |
| 211 | ** Change back all offsets into pointers. | 221 | ** Change back all offsets into pointers. |
| 212 | */ | 222 | */ |
| 213 | static void correctstack (lua_State *L) { | 223 | static void correctstack (lua_State *L, StkId oldstack) { |
| 214 | CallInfo *ci; | 224 | CallInfo *ci; |
| 215 | UpVal *up; | 225 | UpVal *up; |
| 226 | UNUSED(oldstack); | ||
| 216 | L->top.p = restorestack(L, L->top.offset); | 227 | L->top.p = restorestack(L, L->top.offset); |
| 217 | L->tbclist.p = restorestack(L, L->tbclist.offset); | 228 | L->tbclist.p = restorestack(L, L->tbclist.offset); |
| 218 | for (up = L->openupval; up != NULL; up = up->u.open.next) | 229 | for (up = L->openupval; up != NULL; up = up->u.open.next) |
| @@ -225,15 +236,37 @@ static void correctstack (lua_State *L) { | |||
| 225 | } | 236 | } |
| 226 | } | 237 | } |
| 227 | 238 | ||
| 239 | #else | ||
| 240 | /* | ||
| 241 | ** Alternatively, we can use the old address after the dealocation. | ||
| 242 | ** That is not strict ISO C, but seems to work fine everywhere. | ||
| 243 | */ | ||
| 244 | |||
| 245 | static void relstack (lua_State *L) { UNUSED(L); } | ||
| 246 | |||
| 247 | static void correctstack (lua_State *L, StkId oldstack) { | ||
| 248 | CallInfo *ci; | ||
| 249 | UpVal *up; | ||
| 250 | StkId newstack = L->stack.p; | ||
| 251 | if (oldstack == newstack) | ||
| 252 | return; | ||
| 253 | L->top.p = L->top.p - oldstack + newstack; | ||
| 254 | L->tbclist.p = L->tbclist.p - oldstack + newstack; | ||
| 255 | for (up = L->openupval; up != NULL; up = up->u.open.next) | ||
| 256 | up->v.p = s2v(uplevel(up) - oldstack + newstack); | ||
| 257 | for (ci = L->ci; ci != NULL; ci = ci->previous) { | ||
| 258 | ci->top.p = ci->top.p - oldstack + newstack; | ||
| 259 | ci->func.p = ci->func.p - oldstack + newstack; | ||
| 260 | if (isLua(ci)) | ||
| 261 | ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | #endif | ||
| 266 | |||
| 228 | 267 | ||
| 229 | /* | 268 | /* |
| 230 | ** Reallocate the stack to a new size, correcting all pointers into it. | 269 | ** Reallocate the stack to a new size, correcting all pointers into it. |
| 231 | ** In ISO C, any pointer use after the pointer has been deallocated is | ||
| 232 | ** undefined behavior. So, before the reallocation, all pointers are | ||
| 233 | ** changed to offsets, and after the reallocation they are changed back | ||
| 234 | ** to pointers. As during the reallocation the pointers are invalid, the | ||
| 235 | ** reallocation cannot run emergency collections. | ||
| 236 | ** | ||
| 237 | ** In case of allocation error, raise an error or return false according | 270 | ** In case of allocation error, raise an error or return false according |
| 238 | ** to 'raiseerror'. | 271 | ** to 'raiseerror'. |
| 239 | */ | 272 | */ |
| @@ -241,21 +274,22 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | |||
| 241 | int oldsize = stacksize(L); | 274 | int oldsize = stacksize(L); |
| 242 | int i; | 275 | int i; |
| 243 | StkId newstack; | 276 | StkId newstack; |
| 277 | StkId oldstack = L->stack.p; | ||
| 244 | lu_byte oldgcstop = G(L)->gcstopem; | 278 | lu_byte oldgcstop = G(L)->gcstopem; |
| 245 | lua_assert(newsize <= MAXSTACK || newsize == ERRORSTACKSIZE); | 279 | lua_assert(newsize <= MAXSTACK || newsize == ERRORSTACKSIZE); |
| 246 | relstack(L); /* change pointers to offsets */ | 280 | relstack(L); /* change pointers to offsets */ |
| 247 | G(L)->gcstopem = 1; /* stop emergency collection */ | 281 | G(L)->gcstopem = 1; /* stop emergency collection */ |
| 248 | newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK, | 282 | newstack = luaM_reallocvector(L, oldstack, oldsize + EXTRA_STACK, |
| 249 | newsize + EXTRA_STACK, StackValue); | 283 | newsize + EXTRA_STACK, StackValue); |
| 250 | G(L)->gcstopem = oldgcstop; /* restore emergency collection */ | 284 | G(L)->gcstopem = oldgcstop; /* restore emergency collection */ |
| 251 | if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ | 285 | if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ |
| 252 | correctstack(L); /* change offsets back to pointers */ | 286 | correctstack(L, oldstack); /* change offsets back to pointers */ |
| 253 | if (raiseerror) | 287 | if (raiseerror) |
| 254 | luaM_error(L); | 288 | luaM_error(L); |
| 255 | else return 0; /* do not raise an error */ | 289 | else return 0; /* do not raise an error */ |
| 256 | } | 290 | } |
| 257 | L->stack.p = newstack; | 291 | L->stack.p = newstack; |
| 258 | correctstack(L); /* change offsets back to pointers */ | 292 | correctstack(L, oldstack); /* change offsets back to pointers */ |
| 259 | L->stack_last.p = L->stack.p + newsize; | 293 | L->stack_last.p = L->stack.p + newsize; |
| 260 | for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++) | 294 | for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++) |
| 261 | setnilvalue(s2v(newstack + i)); /* erase new segment */ | 295 | setnilvalue(s2v(newstack + i)); /* erase new segment */ |
