浏览代码

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').
Roberto Ierusalimschy 3 年之前
父节点
当前提交
74d99057a5
共有 2 个文件被更改,包括 18 次插入2 次删除
  1. 4 2
      ldo.c
  2. 14 0
      testes/cstack.lua

+ 4 - 2
ldo.c

@@ -759,11 +759,10 @@ static void resume (lua_State *L, void *ud) {
   StkId firstArg = L->top - n;  /* first argument */
   StkId firstArg = L->top - n;  /* first argument */
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   if (L->status == LUA_OK)  /* starting a coroutine? */
   if (L->status == LUA_OK)  /* starting a coroutine? */
-    ccall(L, firstArg - 1, LUA_MULTRET, 1);  /* just call its body */
+    ccall(L, firstArg - 1, LUA_MULTRET, 0);  /* just call its body */
   else {  /* resuming from previous yield */
   else {  /* resuming from previous yield */
     lua_assert(L->status == LUA_YIELD);
     lua_assert(L->status == LUA_YIELD);
     L->status = LUA_OK;  /* mark that it is running (again) */
     L->status = LUA_OK;  /* mark that it is running (again) */
-    luaE_incCstack(L);  /* control the C stack */
     if (isLua(ci)) {  /* yielded inside a hook? */
     if (isLua(ci)) {  /* yielded inside a hook? */
       L->top = firstArg;  /* discard arguments */
       L->top = firstArg;  /* discard arguments */
       luaV_execute(L, ci);  /* just continue running Lua code */
       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,
   else if (L->status != LUA_YIELD)  /* ended with errors? */
   else if (L->status != LUA_YIELD)  /* ended with errors? */
     return resume_error(L, "cannot resume dead coroutine", nargs);
     return resume_error(L, "cannot resume dead coroutine", nargs);
   L->nCcalls = (from) ? getCcalls(from) : 0;
   L->nCcalls = (from) ? getCcalls(from) : 0;
+  if (getCcalls(L) >= LUAI_MAXCCALLS)
+    return resume_error(L, "C stack overflow", nargs);
+  L->nCcalls++;
   luai_userstateresume(L, nargs);
   luai_userstateresume(L, nargs);
   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
   api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
   status = luaD_rawrunprotected(L, resume, &nargs);
   status = luaD_rawrunprotected(L, resume, &nargs);

+ 14 - 0
testes/cstack.lua

@@ -103,6 +103,20 @@ do
 end
 end
 
 
 
 
+do    -- bug in 5.4.2
+  print("nesting coroutines running after recoverable errors")
+  local count = 0
+  local function foo()
+    count = count + 1
+    pcall(1)   -- create an error
+    -- running now inside 'precover' ("protected recover")
+    coroutine.wrap(foo)()   -- call another coroutine
+  end
+  checkerror("C stack overflow", foo)
+  print("final count: ", count)
+end
+
+
 if T then
 if T then
   print("testing stack recovery")
   print("testing stack recovery")
   local N = 0      -- trace number of calls
   local N = 0      -- trace number of calls