aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldo.c68
-rw-r--r--lobject.h6
2 files changed, 52 insertions, 22 deletions
diff --git a/ldo.c b/ldo.c
index d45c74da..c30cde76 100644
--- a/ldo.c
+++ b/ldo.c
@@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
157** Stack reallocation 157** Stack reallocation
158** =================================================================== 158** ===================================================================
159*/ 159*/
160static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { 160
161
162/*
163** Change all pointers to the stack into offsets.
164*/
165static void relstack (lua_State *L) {
166 CallInfo *ci;
167 UpVal *up;
168 L->top.offset = savestack(L, L->top.p);
169 L->tbclist.offset = savestack(L, L->tbclist.p);
170 for (up = L->openupval; up != NULL; up = up->u.open.next)
171 up->v.offset = savestack(L, uplevel(up));
172 for (ci = L->ci; ci != NULL; ci = ci->previous) {
173 ci->top.offset = savestack(L, ci->top.p);
174 ci->func.offset = savestack(L, ci->func.p);
175 }
176}
177
178
179/*
180** Change back all offsets into pointers.
181*/
182static void correctstack (lua_State *L) {
161 CallInfo *ci; 183 CallInfo *ci;
162 UpVal *up; 184 UpVal *up;
163 L->top.p = (L->top.p - oldstack) + newstack; 185 L->top.p = restorestack(L, L->top.offset);
164 L->tbclist.p = (L->tbclist.p - oldstack) + newstack; 186 L->tbclist.p = restorestack(L, L->tbclist.offset);
165 for (up = L->openupval; up != NULL; up = up->u.open.next) 187 for (up = L->openupval; up != NULL; up = up->u.open.next)
166 up->v.p = s2v((uplevel(up) - oldstack) + newstack); 188 up->v.p = s2v(restorestack(L, up->v.offset));
167 for (ci = L->ci; ci != NULL; ci = ci->previous) { 189 for (ci = L->ci; ci != NULL; ci = ci->previous) {
168 ci->top.p = (ci->top.p - oldstack) + newstack; 190 ci->top.p = restorestack(L, ci->top.offset);
169 ci->func.p = (ci->func.p - oldstack) + newstack; 191 ci->func.p = restorestack(L, ci->func.offset);
170 if (isLua(ci)) 192 if (isLua(ci))
171 ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ 193 ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
172 } 194 }
@@ -177,36 +199,38 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
177#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) 199#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
178 200
179/* 201/*
180** Reallocate the stack to a new size, correcting all pointers into 202** Reallocate the stack to a new size, correcting all pointers into it.
181** it. (There are pointers to a stack from its upvalues, from its list 203** In ISO C, any pointer use after the pointer has been deallocated is
182** of call infos, plus a few individual pointers.) The reallocation is 204** undefined behavior. So, before the reallocation, all pointers are
183** done in two steps (allocation + free) because the correction must be 205** changed to offsets, and after the reallocation they are changed back
184** done while both addresses (the old stack and the new one) are valid. 206** to pointers. As during the reallocation the pointers are invalid, the
185** (In ISO C, any pointer use after the pointer has been deallocated is 207** reallocation cannot run emergency collections.
186** undefined behavior.) 208**
187** In case of allocation error, raise an error or return false according 209** In case of allocation error, raise an error or return false according
188** to 'raiseerror'. 210** to 'raiseerror'.
189*/ 211*/
190int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { 212int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
191 int oldsize = stacksize(L); 213 int oldsize = stacksize(L);
192 int i; 214 int i;
193 StkId newstack = luaM_reallocvector(L, NULL, 0, 215 StkId newstack;
194 newsize + EXTRA_STACK, StackValue); 216 int oldgcstop = G(L)->gcstopem;
195 lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); 217 lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
218 relstack(L); /* change pointers to offsets */
219 G(L)->gcstopem = 1; /* stop emergency collection */
220 newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
221 newsize + EXTRA_STACK, StackValue);
222 G(L)->gcstopem = oldgcstop; /* restore emergency collection */
196 if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ 223 if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
224 correctstack(L); /* change offsets back to pointers */
197 if (raiseerror) 225 if (raiseerror)
198 luaM_error(L); 226 luaM_error(L);
199 else return 0; /* do not raise an error */ 227 else return 0; /* do not raise an error */
200 } 228 }
201 /* number of elements to be copied to the new stack */
202 i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
203 memcpy(newstack, L->stack.p, i * sizeof(StackValue));
204 for (; i < newsize + EXTRA_STACK; i++)
205 setnilvalue(s2v(newstack + i)); /* erase new segment */
206 correctstack(L, L->stack.p, newstack);
207 luaM_freearray(L, L->stack.p, oldsize + EXTRA_STACK);
208 L->stack.p = newstack; 229 L->stack.p = newstack;
230 correctstack(L); /* change offsets back to pointers */
209 L->stack_last.p = L->stack.p + newsize; 231 L->stack_last.p = L->stack.p + newsize;
232 for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
233 setnilvalue(s2v(newstack + i)); /* erase new segment */
210 return 1; 234 return 1;
211} 235}
212 236
diff --git a/lobject.h b/lobject.h
index 7af7bd89..e7f58cbd 100644
--- a/lobject.h
+++ b/lobject.h
@@ -158,8 +158,13 @@ typedef union StackValue {
158typedef StackValue *StkId; 158typedef StackValue *StkId;
159 159
160 160
161/*
162** When reallocating the stack, change all pointers to the stack into
163** proper offsets.
164*/
161typedef union { 165typedef union {
162 StkId p; /* actual pointer */ 166 StkId p; /* actual pointer */
167 ptrdiff_t offset; /* used while the stack is being reallocated */
163} StkIdRel; 168} StkIdRel;
164 169
165 170
@@ -626,6 +631,7 @@ typedef struct UpVal {
626 lu_byte tbc; /* true if it represents a to-be-closed variable */ 631 lu_byte tbc; /* true if it represents a to-be-closed variable */
627 union { 632 union {
628 TValue *p; /* points to stack or to its own value */ 633 TValue *p; /* points to stack or to its own value */
634 ptrdiff_t offset; /* used while the stack is being reallocated */
629 } v; 635 } v;
630 union { 636 union {
631 struct { /* (when open) */ 637 struct { /* (when open) */