aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-08-22 11:11:00 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-08-22 11:11:00 -0300
commitfd0e1f530d06340f99334b07d74e5133ce073787 (patch)
tree508a3d85bbba5f0644a8094535b99d0ffdf8c505
parent75620b45ae9d500a3251a0e698de98ab588d2a29 (diff)
downloadlua-fd0e1f530d06340f99334b07d74e5133ce073787.tar.gz
lua-fd0e1f530d06340f99334b07d74e5133ce073787.tar.bz2
lua-fd0e1f530d06340f99334b07d74e5133ce073787.zip
Added option for direct correction of stack pointers
The use of a pointer (not access, only for computations) after its deallocation is forbiden in ISO C, but seems to work fine in all platforms we are aware of. So, using that to correct stack pointers after a stack reallocation seems safe and is much simpler than the current implementation (first change all pointers to offsets and then changing the offsets back to pointers). Anyway, for now that option is disabled.
-rw-r--r--ldo.c54
1 files changed, 44 insertions, 10 deletions
diff --git a/ldo.c b/ldo.c
index d63c8267..e75a79ab 100644
--- a/ldo.c
+++ b/ldo.c
@@ -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*/
196static void relstack (lua_State *L) { 206static 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*/
213static void correctstack (lua_State *L) { 223static 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
245static void relstack (lua_State *L) { UNUSED(L); }
246
247static 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 */