aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldo.c20
-rw-r--r--lgc.c2
-rw-r--r--lstate.c17
-rw-r--r--lstate.h2
-rw-r--r--ltests.c23
-rw-r--r--testes/gc.lua42
-rw-r--r--testes/memerr.lua19
-rw-r--r--testes/tracegc.lua9
8 files changed, 118 insertions, 16 deletions
diff --git a/ldo.c b/ldo.c
index 6d0184ec..12e0364b 100644
--- a/ldo.c
+++ b/ldo.c
@@ -221,13 +221,21 @@ l_noret luaD_errerr (lua_State *L) {
221 221
222 222
223/* 223/*
224** Check whether stack has enough space to run a simple function (such 224** Check whether stacks have enough space to run a simple function (such
225** as a finalizer): At least BASIC_STACK_SIZE in the Lua stack and 225** as a finalizer): At least BASIC_STACK_SIZE in the Lua stack, two
226** 2 slots in the C stack. 226** available CallInfos, and two "slots" in the C stack.
227*/ 227*/
228int luaD_checkminstack (lua_State *L) { 228int luaD_checkminstack (lua_State *L) {
229 return ((stacksize(L) < MAXSTACK - BASIC_STACK_SIZE) && 229 if (getCcalls(L) >= LUAI_MAXCCALLS - 2)
230 (getCcalls(L) < LUAI_MAXCCALLS - 2)); 230 return 0; /* not enough C-stack slots */
231 if (L->ci->next == NULL && luaE_extendCI(L, 0) == NULL)
232 return 0; /* unable to allocate first ci */
233 if (L->ci->next->next == NULL && luaE_extendCI(L, 0) == NULL)
234 return 0; /* unable to allocate second ci */
235 if (L->stack_last.p - L->top.p >= BASIC_STACK_SIZE)
236 return 1; /* enough (BASIC_STACK_SIZE) free slots in the Lua stack */
237 else /* try to grow stack to a size with enough free slots */
238 return luaD_growstack(L, BASIC_STACK_SIZE, 0);
231} 239}
232 240
233 241
@@ -616,7 +624,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
616 624
617 625
618 626
619#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) 627#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L, 1))
620 628
621 629
622/* 630/*
diff --git a/lgc.c b/lgc.c
index f1d9a7ce..0f89451c 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1293,7 +1293,7 @@ static void finishgencycle (lua_State *L, global_State *g) {
1293 correctgraylists(g); 1293 correctgraylists(g);
1294 checkSizes(L, g); 1294 checkSizes(L, g);
1295 g->gcstate = GCSpropagate; /* skip restart */ 1295 g->gcstate = GCSpropagate; /* skip restart */
1296 if (!g->gcemergency && luaD_checkminstack(L)) 1296 if (g->tobefnz != NULL && !g->gcemergency && luaD_checkminstack(L))
1297 callallpendingfinalizers(L); 1297 callallpendingfinalizers(L);
1298} 1298}
1299 1299
diff --git a/lstate.c b/lstate.c
index 70a11aae..7d341991 100644
--- a/lstate.c
+++ b/lstate.c
@@ -68,14 +68,19 @@ void luaE_setdebt (global_State *g, l_mem debt) {
68} 68}
69 69
70 70
71CallInfo *luaE_extendCI (lua_State *L) { 71CallInfo *luaE_extendCI (lua_State *L, int err) {
72 CallInfo *ci; 72 CallInfo *ci;
73 lua_assert(L->ci->next == NULL); 73 ci = luaM_reallocvector(L, NULL, 0, 1, CallInfo);
74 ci = luaM_new(L, CallInfo); 74 if (l_unlikely(ci == NULL)) { /* allocation failed? */
75 lua_assert(L->ci->next == NULL); 75 if (err)
76 L->ci->next = ci; 76 luaM_error(L); /* raise the error */
77 return NULL; /* else only report it */
78 }
79 ci->next = L->ci->next;
77 ci->previous = L->ci; 80 ci->previous = L->ci;
78 ci->next = NULL; 81 L->ci->next = ci;
82 if (ci->next)
83 ci->next->previous = ci;
79 ci->u.l.trap = 0; 84 ci->u.l.trap = 0;
80 L->nci++; 85 L->nci++;
81 return ci; 86 return ci;
diff --git a/lstate.h b/lstate.h
index 20dc4d24..01387283 100644
--- a/lstate.h
+++ b/lstate.h
@@ -438,7 +438,7 @@ union GCUnion {
438LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); 438LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
439LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); 439LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
440LUAI_FUNC lu_mem luaE_threadsize (lua_State *L); 440LUAI_FUNC lu_mem luaE_threadsize (lua_State *L);
441LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); 441LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L, int err);
442LUAI_FUNC void luaE_shrinkCI (lua_State *L); 442LUAI_FUNC void luaE_shrinkCI (lua_State *L);
443LUAI_FUNC void luaE_checkcstack (lua_State *L); 443LUAI_FUNC void luaE_checkcstack (lua_State *L);
444LUAI_FUNC void luaE_incCstack (lua_State *L); 444LUAI_FUNC void luaE_incCstack (lua_State *L);
diff --git a/ltests.c b/ltests.c
index c4905f94..ce2b20ca 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1106,6 +1106,27 @@ static int stacklevel (lua_State *L) {
1106} 1106}
1107 1107
1108 1108
1109static int resetCI (lua_State *L) {
1110 CallInfo *ci = L->ci;
1111 while (ci->next != NULL) {
1112 CallInfo *tofree = ci->next;
1113 ci->next = ci->next->next;
1114 luaM_free(L, tofree);
1115 L->nci--;
1116 }
1117 return 0;
1118}
1119
1120
1121static int reallocstack (lua_State *L) {
1122 int n = cast_int(luaL_checkinteger(L, 1));
1123 lua_lock(L);
1124 luaD_reallocstack(L, cast_int(L->top.p - L->stack.p) + n, 1);
1125 lua_unlock(L);
1126 return 0;
1127}
1128
1129
1109static int table_query (lua_State *L) { 1130static int table_query (lua_State *L) {
1110 const Table *t; 1131 const Table *t;
1111 int i = cast_int(luaL_optinteger(L, 2, -1)); 1132 int i = cast_int(luaL_optinteger(L, 2, -1));
@@ -2182,6 +2203,8 @@ static const struct luaL_Reg tests_funcs[] = {
2182 {"s2d", s2d}, 2203 {"s2d", s2d},
2183 {"sethook", sethook}, 2204 {"sethook", sethook},
2184 {"stacklevel", stacklevel}, 2205 {"stacklevel", stacklevel},
2206 {"resetCI", resetCI},
2207 {"reallocstack", reallocstack},
2185 {"sizes", get_sizes}, 2208 {"sizes", get_sizes},
2186 {"testC", testC}, 2209 {"testC", testC},
2187 {"makeCfunc", makeCfunc}, 2210 {"makeCfunc", makeCfunc},
diff --git a/testes/gc.lua b/testes/gc.lua
index 62713dac..e50d9029 100644
--- a/testes/gc.lua
+++ b/testes/gc.lua
@@ -707,4 +707,46 @@ end
707 707
708collectgarbage(oldmode) 708collectgarbage(oldmode)
709 709
710
711if T then
712 print("testing stack issues when calling finalizers")
713
714 local X
715 local obj
716
717 local function initobj ()
718 X = false
719 obj = setmetatable({}, {__gc = function () X = true end})
720 end
721
722 local function loop (n)
723 if n > 0 then loop(n - 1) end
724 end
725
726 -- should not try to call finalizer without a CallInfo available
727 initobj()
728 loop(20) -- ensure stack space
729 T.resetCI() -- remove extra CallInfos
730 T.alloccount(0) -- cannot allocate more CallInfos
731 obj = nil
732 collectgarbage() -- will not call finalizer
733 T.alloccount()
734 assert(X == false)
735 collectgarbage() -- now will call finalizer (it was still pending)
736 assert(X == true)
737
738 -- should not try to call finalizer without stack space available
739 initobj()
740 loop(5) -- ensure enough CallInfos
741 T.reallocstack(0) -- remove extra stack slots
742 T.alloccount(0) -- cannot reallocate stack
743 obj = nil
744 collectgarbage() -- will not call finalizer
745 T.alloccount()
746 assert(X == false)
747 collectgarbage() -- now will call finalizer (it was still pending)
748 assert(X == true)
749end
750
751
710print('OK') 752print('OK')
diff --git a/testes/memerr.lua b/testes/memerr.lua
index 9c940ca7..a55514a9 100644
--- a/testes/memerr.lua
+++ b/testes/memerr.lua
@@ -282,6 +282,25 @@ testamem("growing stack", function ()
282 return foo(100) 282 return foo(100)
283end) 283end)
284 284
285
286collectgarbage()
287collectgarbage()
288global io, T, setmetatable, collectgarbage, print
289
290local Count = 0
291testamem("finalizers", function ()
292 local X = false
293 local obj = setmetatable({}, {__gc = function () X = true end})
294 obj = nil
295 T.resetCI() -- remove extra CallInfos
296 T.reallocstack(18) -- remove extra stack slots
297 Count = Count + 1
298 io.stderr:write(Count, "\n")
299 T.trick(io)
300 collectgarbage()
301 return X
302end)
303
285-- }================================================================== 304-- }==================================================================
286 305
287 306
diff --git a/testes/tracegc.lua b/testes/tracegc.lua
index a8c929df..c1154f90 100644
--- a/testes/tracegc.lua
+++ b/testes/tracegc.lua
@@ -1,10 +1,15 @@
1-- track collections 1-- track collections
2 2
3
3local M = {} 4local M = {}
4 5
5-- import list 6-- import list
6local setmetatable, stderr, collectgarbage = 7local stderr, collectgarbage = io.stderr, collectgarbage
7 setmetatable, io.stderr, collectgarbage 8
9-- the debug version of setmetatable does not create any object (such as
10-- a '__metatable' string), and so it is more appropriate to be used in
11-- a finalizer
12local setmetatable = require"debug".setmetatable
8 13
9global none 14global none
10 15