aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lapi.c9
-rw-r--r--ldo.c2
-rw-r--r--lfunc.c66
-rw-r--r--lfunc.h9
-rw-r--r--lobject.h10
-rw-r--r--lstate.c15
-rw-r--r--lstate.h2
-rw-r--r--ltests.c1
-rw-r--r--lvm.c6
-rw-r--r--testes/locals.lua49
10 files changed, 103 insertions, 66 deletions
diff --git a/lapi.c b/lapi.c
index 41e6b86d..a9cf2fdb 100644
--- a/lapi.c
+++ b/lapi.c
@@ -192,9 +192,8 @@ LUA_API void lua_settop (lua_State *L, int idx) {
192 if (diff < 0 && hastocloseCfunc(ci->nresults)) 192 if (diff < 0 && hastocloseCfunc(ci->nresults))
193 luaF_close(L, L->top + diff, CLOSEKTOP, 0); 193 luaF_close(L, L->top + diff, CLOSEKTOP, 0);
194#endif 194#endif
195 api_check(L, L->tbclist < L->top + diff, "cannot pop an unclosed slot");
195 L->top += diff; 196 L->top += diff;
196 api_check(L, L->openupval == NULL || uplevel(L->openupval) < L->top,
197 "cannot pop an unclosed slot");
198 lua_unlock(L); 197 lua_unlock(L);
199} 198}
200 199
@@ -203,8 +202,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
203 StkId level; 202 StkId level;
204 lua_lock(L); 203 lua_lock(L);
205 level = index2stack(L, idx); 204 level = index2stack(L, idx);
206 api_check(L, hastocloseCfunc(L->ci->nresults) && L->openupval != NULL && 205 api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
207 uplevel(L->openupval) == level,
208 "no variable to close at given level"); 206 "no variable to close at given level");
209 luaF_close(L, level, CLOSEKTOP, 0); 207 luaF_close(L, level, CLOSEKTOP, 0);
210 level = index2stack(L, idx); /* stack may be moved */ 208 level = index2stack(L, idx); /* stack may be moved */
@@ -1266,8 +1264,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
1266 lua_lock(L); 1264 lua_lock(L);
1267 o = index2stack(L, idx); 1265 o = index2stack(L, idx);
1268 nresults = L->ci->nresults; 1266 nresults = L->ci->nresults;
1269 api_check(L, L->openupval == NULL || uplevel(L->openupval) <= o, 1267 api_check(L, L->tbclist < o, "given index below or equal a marked one");
1270 "marked index below or equal new one");
1271 luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ 1268 luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
1272 if (!hastocloseCfunc(nresults)) /* function not marked yet? */ 1269 if (!hastocloseCfunc(nresults)) /* function not marked yet? */
1273 L->ci->nresults = codeNresults(nresults); /* mark it */ 1270 L->ci->nresults = codeNresults(nresults); /* mark it */
diff --git a/ldo.c b/ldo.c
index 65f0a7b9..bc7212c6 100644
--- a/ldo.c
+++ b/ldo.c
@@ -163,7 +163,7 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
163 if (oldstack == newstack) 163 if (oldstack == newstack)
164 return; /* stack address did not change */ 164 return; /* stack address did not change */
165 L->top = (L->top - oldstack) + newstack; 165 L->top = (L->top - oldstack) + newstack;
166 lua_assert(L->ptbc == NULL); 166 L->tbclist = (L->tbclist - oldstack) + newstack;
167 for (up = L->openupval; up != NULL; up = up->u.open.next) 167 for (up = L->openupval; up != NULL; up = up->u.open.next)
168 up->v = s2v((uplevel(up) - oldstack) + newstack); 168 up->v = s2v((uplevel(up) - oldstack) + newstack);
169 for (ci = L->ci; ci != NULL; ci = ci->previous) { 169 for (ci = L->ci; ci != NULL; ci = ci->previous) {
diff --git a/lfunc.c b/lfunc.c
index 105590fc..b4c04bd0 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -120,11 +120,11 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
120 120
121 121
122/* 122/*
123** Check whether 'obj' has a close metamethod and raise an error 123** Check whether object at given level has a close metamethod and raise
124** if not. 124** an error if not.
125*/ 125*/
126static void checkclosemth (lua_State *L, StkId level, const TValue *obj) { 126static void checkclosemth (lua_State *L, StkId level) {
127 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); 127 const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
128 if (ttisnil(tm)) { /* no metamethod? */ 128 if (ttisnil(tm)) { /* no metamethod? */
129 int idx = cast_int(level - L->ci->func); /* variable index */ 129 int idx = cast_int(level - L->ci->func); /* variable index */
130 const char *vname = luaG_findlocal(L, L->ci, idx, NULL); 130 const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
@@ -155,20 +155,21 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
155 155
156 156
157/* 157/*
158** Create a to-be-closed upvalue. If there is a memory allocation error, 158** Insert a variable in the list of to-be-closed variables.
159** 'ptbc' keeps the object so it can be closed as soon as possible.
160** (Since memory errors have no handler, that will happen before any
161** stack reallocation.)
162*/ 159*/
163void luaF_newtbcupval (lua_State *L, StkId level) { 160void luaF_newtbcupval (lua_State *L, StkId level) {
164 TValue *obj = s2v(level); 161 lua_assert(level > L->tbclist);
165 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); 162 if (l_isfalse(s2v(level)))
166 if (!l_isfalse(obj)) { /* false doesn't need to be closed */ 163 return; /* false doesn't need to be closed */
167 checkclosemth(L, level, obj); 164 checkclosemth(L, level); /* value must have a close method */
168 L->ptbc = level; /* in case of allocation error */ 165 while (level - L->tbclist > USHRT_MAX) { /* is delta too large? */
169 newupval(L, 1, level, &L->openupval); 166 L->tbclist += USHRT_MAX; /* create a dummy node at maximum delta */
170 L->ptbc = NULL; /* no errors */ 167 L->tbclist->tbclist.delta = USHRT_MAX;
168 L->tbclist->tbclist.isdummy = 1;
171 } 169 }
170 level->tbclist.delta = level - L->tbclist;
171 level->tbclist.isdummy = 0;
172 L->tbclist = level;
172} 173}
173 174
174 175
@@ -181,23 +182,11 @@ void luaF_unlinkupval (UpVal *uv) {
181 182
182 183
183/* 184/*
184** Close all upvalues up to the given stack level. A 'status' equal 185** Close all upvalues up to the given stack level.
185** to NOCLOSINGMETH closes upvalues without running any __close
186** metamethods. If there is a pending to-be-closed value, close
187** it before anything else.
188*/ 186*/
189void luaF_close (lua_State *L, StkId level, int status, int yy) { 187void luaF_closeupval (lua_State *L, StkId level) {
190 UpVal *uv; 188 UpVal *uv;
191 StkId upl; /* stack index pointed by 'uv' */ 189 StkId upl; /* stack index pointed by 'uv' */
192 if (unlikely(status == LUA_ERRMEM && L->ptbc != NULL)) {
193 ptrdiff_t levelrel = savestack(L, level);
194 upl = L->ptbc;
195 L->ptbc = NULL; /* remove from "list" before closing */
196 prepcallclosemth(L, upl, status, yy);
197 level = restorestack(L, levelrel);
198 }
199 else
200 lua_assert(L->ptbc == NULL); /* must be empty for other status */
201 while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { 190 while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
202 TValue *slot = &uv->u.value; /* new position for value */ 191 TValue *slot = &uv->u.value; /* new position for value */
203 lua_assert(uplevel(uv) < L->top); 192 lua_assert(uplevel(uv) < L->top);
@@ -208,9 +197,22 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) {
208 nw2black(uv); /* closed upvalues cannot be gray */ 197 nw2black(uv); /* closed upvalues cannot be gray */
209 luaC_barrier(L, uv, slot); 198 luaC_barrier(L, uv, slot);
210 } 199 }
211 if (uv->tbc && status != NOCLOSINGMETH) { 200 }
212 ptrdiff_t levelrel = savestack(L, level); 201}
213 prepcallclosemth(L, upl, status, yy); /* may change the stack */ 202
203
204/*
205** Close all upvalues and to-be-closed variables up to the given stack
206** level.
207*/
208void luaF_close (lua_State *L, StkId level, int status, int yy) {
209 ptrdiff_t levelrel = savestack(L, level);
210 luaF_closeupval(L, level); /* first, close the upvalues */
211 while (L->tbclist >= level) { /* traverse tbc's down to that level */
212 StkId tbc = L->tbclist; /* get variable index */
213 L->tbclist -= tbc->tbclist.delta; /* remove it from list */
214 if (!tbc->tbclist.isdummy) { /* not a dummy entry? */
215 prepcallclosemth(L, tbc, status, yy); /* close variable */
214 level = restorestack(L, levelrel); 216 level = restorestack(L, levelrel);
215 } 217 }
216 } 218 }
diff --git a/lfunc.h b/lfunc.h
index 2e6df535..dc1cebcc 100644
--- a/lfunc.h
+++ b/lfunc.h
@@ -42,15 +42,9 @@
42#define MAXMISS 10 42#define MAXMISS 10
43 43
44 44
45/*
46** Special "status" for 'luaF_close'
47*/
48
49/* close upvalues without running their closing methods */
50#define NOCLOSINGMETH (-1)
51 45
52/* special status to close upvalues preserving the top of the stack */ 46/* special status to close upvalues preserving the top of the stack */
53#define CLOSEKTOP (-2) 47#define CLOSEKTOP (-1)
54 48
55 49
56LUAI_FUNC Proto *luaF_newproto (lua_State *L); 50LUAI_FUNC Proto *luaF_newproto (lua_State *L);
@@ -59,6 +53,7 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals);
59LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); 53LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
60LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); 54LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
61LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); 55LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
56LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
62LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); 57LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
63LUAI_FUNC void luaF_unlinkupval (UpVal *uv); 58LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
64LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); 59LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
diff --git a/lobject.h b/lobject.h
index 470b17d5..1a7a7372 100644
--- a/lobject.h
+++ b/lobject.h
@@ -136,10 +136,18 @@ typedef struct TValue {
136 136
137 137
138/* 138/*
139** Entries in the Lua stack 139** Entries in a Lua stack. Field 'tbclist' forms a list of all
140** to-be-closed variables active in this stack. Dummy entries are
141** used when the distance between two tbc variables does not fit
142** in an unsigned short.
140*/ 143*/
141typedef union StackValue { 144typedef union StackValue {
142 TValue val; 145 TValue val;
146 struct {
147 TValuefields;
148 lu_byte isdummy;
149 unsigned short delta;
150 } tbclist;
143} StackValue; 151} StackValue;
144 152
145 153
diff --git a/lstate.c b/lstate.c
index 52336f44..38078521 100644
--- a/lstate.c
+++ b/lstate.c
@@ -181,6 +181,7 @@ static void stack_init (lua_State *L1, lua_State *L) {
181 int i; CallInfo *ci; 181 int i; CallInfo *ci;
182 /* initialize stack array */ 182 /* initialize stack array */
183 L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); 183 L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
184 L1->tbclist = L1->stack;
184 for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) 185 for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
185 setnilvalue(s2v(L1->stack + i)); /* erase new stack */ 186 setnilvalue(s2v(L1->stack + i)); /* erase new stack */
186 L1->top = L1->stack; 187 L1->top = L1->stack;
@@ -262,16 +263,18 @@ static void preinit_thread (lua_State *L, global_State *g) {
262 L->status = LUA_OK; 263 L->status = LUA_OK;
263 L->errfunc = 0; 264 L->errfunc = 0;
264 L->oldpc = 0; 265 L->oldpc = 0;
265 L->ptbc = NULL;
266} 266}
267 267
268 268
269static void close_state (lua_State *L) { 269static void close_state (lua_State *L) {
270 global_State *g = G(L); 270 global_State *g = G(L);
271 luaD_closeprotected(L, 0, LUA_OK); /* close all upvalues */ 271 if (!completestate(g)) /* closing a partially built state? */
272 luaC_freeallobjects(L); /* collect all objects */ 272 luaC_freeallobjects(L); /* jucst collect its objects */
273 if (completestate(g)) /* closing a fully built state? */ 273 else { /* closing a fully built state */
274 luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
275 luaC_freeallobjects(L); /* collect all objects */
274 luai_userstateclose(L); 276 luai_userstateclose(L);
277 }
275 luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); 278 luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
276 freestack(L); 279 freestack(L);
277 lua_assert(gettotalbytes(g) == sizeof(LG)); 280 lua_assert(gettotalbytes(g) == sizeof(LG));
@@ -312,7 +315,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
312 315
313void luaE_freethread (lua_State *L, lua_State *L1) { 316void luaE_freethread (lua_State *L, lua_State *L1) {
314 LX *l = fromstate(L1); 317 LX *l = fromstate(L1);
315 luaF_close(L1, L1->stack, NOCLOSINGMETH, 0); /* close all upvalues */ 318 luaF_closeupval(L1, L1->stack); /* close all upvalues */
316 lua_assert(L1->openupval == NULL); 319 lua_assert(L1->openupval == NULL);
317 luai_userstatefree(L, L1); 320 luai_userstatefree(L, L1);
318 freestack(L1); 321 freestack(L1);
@@ -327,7 +330,7 @@ int luaE_resetthread (lua_State *L, int status) {
327 ci->callstatus = CIST_C; 330 ci->callstatus = CIST_C;
328 if (status == LUA_YIELD) 331 if (status == LUA_YIELD)
329 status = LUA_OK; 332 status = LUA_OK;
330 status = luaD_closeprotected(L, 0, status); 333 status = luaD_closeprotected(L, 1, status);
331 if (status != LUA_OK) /* errors? */ 334 if (status != LUA_OK) /* errors? */
332 luaD_seterrorobj(L, status, L->stack + 1); 335 luaD_seterrorobj(L, status, L->stack + 1);
333 else 336 else
diff --git a/lstate.h b/lstate.h
index 5ef55355..b6ade7c7 100644
--- a/lstate.h
+++ b/lstate.h
@@ -307,6 +307,7 @@ struct lua_State {
307 StkId stack_last; /* end of stack (last element + 1) */ 307 StkId stack_last; /* end of stack (last element + 1) */
308 StkId stack; /* stack base */ 308 StkId stack; /* stack base */
309 UpVal *openupval; /* list of open upvalues in this stack */ 309 UpVal *openupval; /* list of open upvalues in this stack */
310 StkId tbclist; /* list of to-be-closed variables */
310 GCObject *gclist; 311 GCObject *gclist;
311 struct lua_State *twups; /* list of threads with open upvalues */ 312 struct lua_State *twups; /* list of threads with open upvalues */
312 struct lua_longjmp *errorJmp; /* current error recover point */ 313 struct lua_longjmp *errorJmp; /* current error recover point */
@@ -318,7 +319,6 @@ struct lua_State {
318 int basehookcount; 319 int basehookcount;
319 int hookcount; 320 int hookcount;
320 volatile l_signalT hookmask; 321 volatile l_signalT hookmask;
321 StkId ptbc; /* pending to-be-closed variable */
322}; 322};
323 323
324 324
diff --git a/ltests.c b/ltests.c
index 9c13338a..da95d027 100644
--- a/ltests.c
+++ b/ltests.c
@@ -446,6 +446,7 @@ static void checkstack (global_State *g, lua_State *L1) {
446 for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) 446 for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
447 assert(upisopen(uv)); /* must be open */ 447 assert(upisopen(uv)); /* must be open */
448 assert(L1->top <= L1->stack_last); 448 assert(L1->top <= L1->stack_last);
449 assert(L1->tbclist <= L1->top);
449 for (ci = L1->ci; ci != NULL; ci = ci->previous) { 450 for (ci = L1->ci; ci != NULL; ci = ci->previous) {
450 assert(ci->top <= L1->stack_last); 451 assert(ci->top <= L1->stack_last);
451 assert(lua_checkpc(ci)); 452 assert(lua_checkpc(ci));
diff --git a/lvm.c b/lvm.c
index e9b1dcdd..1252ecbf 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1635,10 +1635,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1635 b = cast_int(L->top - ra); 1635 b = cast_int(L->top - ra);
1636 savepc(ci); /* several calls here can raise errors */ 1636 savepc(ci); /* several calls here can raise errors */
1637 if (TESTARG_k(i)) { 1637 if (TESTARG_k(i)) {
1638 /* close upvalues from current call; the compiler ensures 1638 luaF_closeupval(L, base); /* close upvalues from current call */
1639 that there are no to-be-closed variables here, so this 1639 lua_assert(L->tbclist < base); /* no pending tbc variables */
1640 call cannot change the stack */
1641 luaF_close(L, base, NOCLOSINGMETH, 0);
1642 lua_assert(base == ci->func + 1); 1640 lua_assert(base == ci->func + 1);
1643 } 1641 }
1644 while (!ttisfunction(s2v(ra))) { /* not a function? */ 1642 while (!ttisfunction(s2v(ra))) { /* not a function? */
diff --git a/testes/locals.lua b/testes/locals.lua
index a25b2b9f..446ec13a 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -529,6 +529,40 @@ local function checktable (t1, t2)
529end 529end
530 530
531 531
532do -- test for tbc variable high in the stack
533
534 -- function to force a stack overflow
535 local function overflow (n)
536 overflow(n + 1)
537 end
538
539 -- error handler will create tbc variable handling a stack overflow,
540 -- high in the stack
541 local function errorh (m)
542 assert(string.find(m, "stack overflow"))
543 local x <close> = func2close(function (o) o[1] = 10 end)
544 return x
545 end
546
547 local flag
548 local st, obj
549 -- run test in a coroutine so as not to swell the main stack
550 local co = coroutine.wrap(function ()
551 -- tbc variable down the stack
552 local y <close> = func2close(function (obj, msg)
553 assert(msg == nil)
554 obj[1] = 100
555 flag = obj
556 end)
557 collectgarbage("stop")
558 st, obj = xpcall(overflow, errorh, 0)
559 collectgarbage("restart")
560 end)
561 co()
562 assert(not st and obj[1] == 10 and flag[1] == 100)
563end
564
565
532if rawget(_G, "T") then 566if rawget(_G, "T") then
533 567
534 -- memory error inside closing function 568 -- memory error inside closing function
@@ -563,13 +597,13 @@ if rawget(_G, "T") then
563 597
564 local function test () 598 local function test ()
565 local x <close> = enter(0) -- set a memory limit 599 local x <close> = enter(0) -- set a memory limit
566 -- creation of previous upvalue will raise a memory error 600 local y = {} -- raise a memory error
567 assert(false) -- should not run
568 end 601 end
569 602
570 local _, msg = pcall(test) 603 local _, msg = pcall(test)
571 assert(msg == "not enough memory" and closemsg == "not enough memory") 604 assert(msg == "not enough memory" and closemsg == "not enough memory")
572 605
606
573 -- repeat test with extra closing upvalues 607 -- repeat test with extra closing upvalues
574 local function test () 608 local function test ()
575 local xxx <close> = func2close(function (self, msg) 609 local xxx <close> = func2close(function (self, msg)
@@ -580,8 +614,7 @@ if rawget(_G, "T") then
580 assert(msg == "not enough memory"); 614 assert(msg == "not enough memory");
581 end) 615 end)
582 local x <close> = enter(0) -- set a memory limit 616 local x <close> = enter(0) -- set a memory limit
583 -- creation of previous upvalue will raise a memory error 617 local y = {} -- raise a memory error
584 os.exit(false) -- should not run
585 end 618 end
586 619
587 local _, msg = pcall(test) 620 local _, msg = pcall(test)
@@ -607,7 +640,7 @@ if rawget(_G, "T") then
607 -- concat this table needs two buffer resizes (one for each 's') 640 -- concat this table needs two buffer resizes (one for each 's')
608 local a = {s, s} 641 local a = {s, s}
609 642
610 collectgarbage() 643 collectgarbage(); collectgarbage()
611 644
612 m = T.totalmem() 645 m = T.totalmem()
613 collectgarbage("stop") 646 collectgarbage("stop")
@@ -630,7 +663,7 @@ if rawget(_G, "T") then
630 -- second buffer was released by 'toclose' 663 -- second buffer was released by 'toclose'
631 assert(T.totalmem() - m <= extra) 664 assert(T.totalmem() - m <= extra)
632 665
633 -- userdata, upvalue, buffer, buffer, final string 666 -- userdata, buffer, buffer, final string
634 T.totalmem(m + 4*lim + extra) 667 T.totalmem(m + 4*lim + extra)
635 assert(#table.concat(a) == 2*lim) 668 assert(#table.concat(a) == 2*lim)
636 669
@@ -753,8 +786,8 @@ do
753 checktable({co()}, {true, 10, 20, 30}) 786 checktable({co()}, {true, 10, 20, 30})
754 checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"}) 787 checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"})
755 788
756end 789end
757 790
758 791
759do 792do
760 -- yielding inside closing metamethods after an error 793 -- yielding inside closing metamethods after an error