diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-11-03 15:04:18 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-11-03 15:04:18 -0300 |
commit | 74d99057a5146755e737c479850f87fd0e3b6868 (patch) | |
tree | db3f0b0bc146572c0e6d9508543cd79be15dd875 | |
parent | 1fce5bea817de50e055a84c153a975f25bfcf493 (diff) | |
download | lua-74d99057a5146755e737c479850f87fd0e3b6868.tar.gz lua-74d99057a5146755e737c479850f87fd0e3b6868.tar.bz2 lua-74d99057a5146755e737c479850f87fd0e3b6868.zip |
Bug: C stack overflow with coroutines
'coroutine.resume' did not increment counter of C calls when
continuing execution after a protected error (that is,
while running 'precover').
-rw-r--r-- | ldo.c | 6 | ||||
-rw-r--r-- | testes/cstack.lua | 14 |
2 files changed, 18 insertions, 2 deletions
@@ -759,11 +759,10 @@ static void resume (lua_State *L, void *ud) { | |||
759 | StkId firstArg = L->top - n; /* first argument */ | 759 | StkId firstArg = L->top - n; /* first argument */ |
760 | CallInfo *ci = L->ci; | 760 | CallInfo *ci = L->ci; |
761 | if (L->status == LUA_OK) /* starting a coroutine? */ | 761 | if (L->status == LUA_OK) /* starting a coroutine? */ |
762 | ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */ | 762 | ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ |
763 | else { /* resuming from previous yield */ | 763 | else { /* resuming from previous yield */ |
764 | lua_assert(L->status == LUA_YIELD); | 764 | lua_assert(L->status == LUA_YIELD); |
765 | L->status = LUA_OK; /* mark that it is running (again) */ | 765 | L->status = LUA_OK; /* mark that it is running (again) */ |
766 | luaE_incCstack(L); /* control the C stack */ | ||
767 | if (isLua(ci)) { /* yielded inside a hook? */ | 766 | if (isLua(ci)) { /* yielded inside a hook? */ |
768 | L->top = firstArg; /* discard arguments */ | 767 | L->top = firstArg; /* discard arguments */ |
769 | luaV_execute(L, ci); /* just continue running Lua code */ | 768 | luaV_execute(L, ci); /* just continue running Lua code */ |
@@ -814,6 +813,9 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
814 | else if (L->status != LUA_YIELD) /* ended with errors? */ | 813 | else if (L->status != LUA_YIELD) /* ended with errors? */ |
815 | return resume_error(L, "cannot resume dead coroutine", nargs); | 814 | return resume_error(L, "cannot resume dead coroutine", nargs); |
816 | L->nCcalls = (from) ? getCcalls(from) : 0; | 815 | L->nCcalls = (from) ? getCcalls(from) : 0; |
816 | if (getCcalls(L) >= LUAI_MAXCCALLS) | ||
817 | return resume_error(L, "C stack overflow", nargs); | ||
818 | L->nCcalls++; | ||
817 | luai_userstateresume(L, nargs); | 819 | luai_userstateresume(L, nargs); |
818 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 820 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
819 | status = luaD_rawrunprotected(L, resume, &nargs); | 821 | status = luaD_rawrunprotected(L, resume, &nargs); |
diff --git a/testes/cstack.lua b/testes/cstack.lua index 213d15d4..ca76c872 100644 --- a/testes/cstack.lua +++ b/testes/cstack.lua | |||
@@ -103,6 +103,20 @@ do | |||
103 | end | 103 | end |
104 | 104 | ||
105 | 105 | ||
106 | do -- bug in 5.4.2 | ||
107 | print("nesting coroutines running after recoverable errors") | ||
108 | local count = 0 | ||
109 | local function foo() | ||
110 | count = count + 1 | ||
111 | pcall(1) -- create an error | ||
112 | -- running now inside 'precover' ("protected recover") | ||
113 | coroutine.wrap(foo)() -- call another coroutine | ||
114 | end | ||
115 | checkerror("C stack overflow", foo) | ||
116 | print("final count: ", count) | ||
117 | end | ||
118 | |||
119 | |||
106 | if T then | 120 | if T then |
107 | print("testing stack recovery") | 121 | print("testing stack recovery") |
108 | local N = 0 -- trace number of calls | 122 | local N = 0 -- trace number of calls |