Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 921832b

Browse files
committed
New function 'resetCI'
New function 'resetCI' resets the CallInfo list of a thread, ensuring a proper state when creating a new thread, closing a thread, or closing a state, so that we can run code after that. (When closing a thread, we need to run its __close metamethods; when closing a state, we need to run its __close metamethods and its finalizers.)
1 parent 205f9aa commit 921832b

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

lstate.c

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -143,25 +143,29 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
143143
}
144144

145145

146+
static void resetCI (lua_State *L) {
147+
CallInfo *ci = L->ci = &L->base_ci;
148+
ci->func.p = L->stack.p;
149+
setnilvalue(s2v(ci->func.p)); /* 'function' entry for basic 'ci' */
150+
ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */
151+
ci->u.c.k = NULL;
152+
ci->callstatus = CIST_C;
153+
L->status = LUA_OK;
154+
L->errfunc = 0; /* stack unwind can "throw away" the error function */
155+
}
156+
157+
146158
static void stack_init (lua_State *L1, lua_State *L) {
147-
int i; CallInfo *ci;
159+
int i;
148160
/* initialize stack array */
149161
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
150162
L1->tbclist.p = L1->stack.p;
151163
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
152164
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
153-
L1->top.p = L1->stack.p;
154165
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
155166
/* initialize first ci */
156-
ci = &L1->base_ci;
157-
ci->next = ci->previous = NULL;
158-
ci->callstatus = CIST_C;
159-
ci->func.p = L1->top.p;
160-
ci->u.c.k = NULL;
161-
setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
162-
L1->top.p++;
163-
ci->top.p = L1->top.p + LUA_MINSTACK;
164-
L1->ci = ci;
167+
resetCI(L1);
168+
L1->top.p = L1->stack.p + 1; /* +1 for 'function' entry */
165169
}
166170

167171

@@ -235,6 +239,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
235239
L->status = LUA_OK;
236240
L->errfunc = 0;
237241
L->oldpc = 0;
242+
L->base_ci.previous = L->base_ci.next = NULL;
238243
}
239244

240245

@@ -252,8 +257,9 @@ static void close_state (lua_State *L) {
252257
if (!completestate(g)) /* closing a partially built state? */
253258
luaC_freeallobjects(L); /* just collect its objects */
254259
else { /* closing a fully built state */
255-
L->ci = &L->base_ci; /* unwind CallInfo list */
260+
resetCI(L);
256261
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
262+
L->top.p = L->stack.p + 1; /* empty the stack to run finalizers */
257263
luaC_freeallobjects(L); /* collect all objects */
258264
luai_userstateclose(L);
259265
}
@@ -302,20 +308,15 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
302308

303309

304310
TStatus luaE_resetthread (lua_State *L, TStatus status) {
305-
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
306-
setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
307-
ci->func.p = L->stack.p;
308-
ci->callstatus = CIST_C;
311+
resetCI(L);
309312
if (status == LUA_YIELD)
310313
status = LUA_OK;
311-
L->status = LUA_OK; /* so it can run __close metamethods */
312314
status = luaD_closeprotected(L, 1, status);
313315
if (status != LUA_OK) /* errors? */
314316
luaD_seterrorobj(L, status, L->stack.p + 1);
315317
else
316318
L->top.p = L->stack.p + 1;
317-
ci->top.p = L->top.p + LUA_MINSTACK;
318-
luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
319+
luaD_reallocstack(L, cast_int(L->ci->top.p - L->stack.p), 0);
319320
return status;
320321
}
321322

testes/coroutine.lua

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,25 @@ assert(not pcall(a, a))
505505
a = nil
506506

507507

508+
do
509+
-- bug in 5.4: thread can use message handler higher in the stack
510+
-- than the variable being closed
511+
local c = coroutine.create(function()
512+
local clo <close> = setmetatable({}, {__close=function()
513+
local x = 134 -- will overwrite message handler
514+
error(x)
515+
end})
516+
-- yields coroutine but leaves a new message handler for it,
517+
-- that would be used when closing the coroutine (except that it
518+
-- will be overwritten)
519+
xpcall(coroutine.yield, function() return "XXX" end)
520+
end)
521+
522+
assert(coroutine.resume(c)) -- start coroutine
523+
local st, msg = coroutine.close(c)
524+
assert(not st and msg == 134)
525+
end
526+
508527
-- access to locals of erroneous coroutines
509528
local x = coroutine.create (function ()
510529
local a = 10

0 commit comments

Comments
 (0)