mirror of
https://github.com/lua/lua
synced 2024-11-22 04:41:23 +03:00
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.
This commit is contained in:
parent
75620b45ae
commit
fd0e1f530d
54
ldo.c
54
ldo.c
@ -190,6 +190,16 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
|||||||
#define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE)
|
#define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** In ISO C, any pointer use after the pointer has been deallocated is
|
||||||
|
** undefined behavior. So, before a stack reallocation, all pointers are
|
||||||
|
** changed to offsets, and after the reallocation they are changed back
|
||||||
|
** to pointers. As during the reallocation the pointers are invalid, the
|
||||||
|
** reallocation cannot run emergency collections.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 1
|
||||||
/*
|
/*
|
||||||
** Change all pointers to the stack into offsets.
|
** Change all pointers to the stack into offsets.
|
||||||
*/
|
*/
|
||||||
@ -210,9 +220,10 @@ static void relstack (lua_State *L) {
|
|||||||
/*
|
/*
|
||||||
** Change back all offsets into pointers.
|
** Change back all offsets into pointers.
|
||||||
*/
|
*/
|
||||||
static void correctstack (lua_State *L) {
|
static void correctstack (lua_State *L, StkId oldstack) {
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
UpVal *up;
|
UpVal *up;
|
||||||
|
UNUSED(oldstack);
|
||||||
L->top.p = restorestack(L, L->top.offset);
|
L->top.p = restorestack(L, L->top.offset);
|
||||||
L->tbclist.p = restorestack(L, L->tbclist.offset);
|
L->tbclist.p = restorestack(L, L->tbclist.offset);
|
||||||
for (up = L->openupval; up != NULL; up = up->u.open.next)
|
for (up = L->openupval; up != NULL; up = up->u.open.next)
|
||||||
@ -225,15 +236,37 @@ static void correctstack (lua_State *L) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
** Alternatively, we can use the old address after the dealocation.
|
||||||
|
** That is not strict ISO C, but seems to work fine everywhere.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void relstack (lua_State *L) { UNUSED(L); }
|
||||||
|
|
||||||
|
static void correctstack (lua_State *L, StkId oldstack) {
|
||||||
|
CallInfo *ci;
|
||||||
|
UpVal *up;
|
||||||
|
StkId newstack = L->stack.p;
|
||||||
|
if (oldstack == newstack)
|
||||||
|
return;
|
||||||
|
L->top.p = L->top.p - oldstack + newstack;
|
||||||
|
L->tbclist.p = L->tbclist.p - oldstack + newstack;
|
||||||
|
for (up = L->openupval; up != NULL; up = up->u.open.next)
|
||||||
|
up->v.p = s2v(uplevel(up) - oldstack + newstack);
|
||||||
|
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||||
|
ci->top.p = ci->top.p - oldstack + newstack;
|
||||||
|
ci->func.p = ci->func.p - oldstack + newstack;
|
||||||
|
if (isLua(ci))
|
||||||
|
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Reallocate the stack to a new size, correcting all pointers into it.
|
** Reallocate the stack to a new size, correcting all pointers into it.
|
||||||
** In ISO C, any pointer use after the pointer has been deallocated is
|
|
||||||
** undefined behavior. So, before the reallocation, all pointers are
|
|
||||||
** changed to offsets, and after the reallocation they are changed back
|
|
||||||
** to pointers. As during the reallocation the pointers are invalid, the
|
|
||||||
** reallocation cannot run emergency collections.
|
|
||||||
**
|
|
||||||
** In case of allocation error, raise an error or return false according
|
** In case of allocation error, raise an error or return false according
|
||||||
** to 'raiseerror'.
|
** to 'raiseerror'.
|
||||||
*/
|
*/
|
||||||
@ -241,21 +274,22 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
|
|||||||
int oldsize = stacksize(L);
|
int oldsize = stacksize(L);
|
||||||
int i;
|
int i;
|
||||||
StkId newstack;
|
StkId newstack;
|
||||||
|
StkId oldstack = L->stack.p;
|
||||||
lu_byte oldgcstop = G(L)->gcstopem;
|
lu_byte oldgcstop = G(L)->gcstopem;
|
||||||
lua_assert(newsize <= MAXSTACK || newsize == ERRORSTACKSIZE);
|
lua_assert(newsize <= MAXSTACK || newsize == ERRORSTACKSIZE);
|
||||||
relstack(L); /* change pointers to offsets */
|
relstack(L); /* change pointers to offsets */
|
||||||
G(L)->gcstopem = 1; /* stop emergency collection */
|
G(L)->gcstopem = 1; /* stop emergency collection */
|
||||||
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
|
newstack = luaM_reallocvector(L, oldstack, oldsize + EXTRA_STACK,
|
||||||
newsize + EXTRA_STACK, StackValue);
|
newsize + EXTRA_STACK, StackValue);
|
||||||
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
|
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
|
||||||
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
|
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
|
||||||
correctstack(L); /* change offsets back to pointers */
|
correctstack(L, oldstack); /* change offsets back to pointers */
|
||||||
if (raiseerror)
|
if (raiseerror)
|
||||||
luaM_error(L);
|
luaM_error(L);
|
||||||
else return 0; /* do not raise an error */
|
else return 0; /* do not raise an error */
|
||||||
}
|
}
|
||||||
L->stack.p = newstack;
|
L->stack.p = newstack;
|
||||||
correctstack(L); /* change offsets back to pointers */
|
correctstack(L, oldstack); /* change offsets back to pointers */
|
||||||
L->stack_last.p = L->stack.p + newsize;
|
L->stack_last.p = L->stack.p + newsize;
|
||||||
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
|
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
|
||||||
setnilvalue(s2v(newstack + i)); /* erase new segment */
|
setnilvalue(s2v(newstack + i)); /* erase new segment */
|
||||||
|
Loading…
Reference in New Issue
Block a user