diff options
Diffstat (limited to 'ldo.c')
-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 */ |