Răsfoiți Sursa

error messages from 'lua_resume' must be generated in protected mode,
to avoid raising memory errors

Roberto Ierusalimschy 15 ani în urmă
părinte
comite
2643da67c6
1 a modificat fișierele cu 43 adăugiri și 36 ștergeri
  1. 43 36
      ldo.c

+ 43 - 36
ldo.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: ldo.c,v 2.73 2009/11/25 15:27:51 roberto Exp roberto $
+** $Id: ldo.c,v 2.74 2009/11/27 15:37:59 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -404,19 +404,38 @@ static void unroll (lua_State *L, void *ud) {
 }
 }
 
 
 
 
+/*
+** data to be passed to 'resume' by 'lua_resume'
+*/
+struct ResumeData {
+  StkId firstArg;  /* stack index of first argument */
+  int recover;  /* should try to recover in case of errors */
+};
+
+
+/*
+** do the work for 'lua_resume' in protected mode
+*/
 static void resume (lua_State *L, void *ud) {
 static void resume (lua_State *L, void *ud) {
-  StkId firstArg = cast(StkId, ud);
+  struct ResumeData *rd = cast(struct ResumeData *, ud);
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
-  if (L->status == LUA_OK) {  /* start coroutine? */
-    lua_assert(ci == &L->base_ci);
-    if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */
+  if (G(L)->nCcalls >= LUAI_MAXCCALLS)
+    luaG_runerror(L, "C stack overflow");
+  if (L->status == LUA_OK) {  /* may be starting a coroutine */
+    if (ci != &L->base_ci) {  /* not in base level? */
+      rd->recover = 0;  /* thread may not be running as a coroutine */
+      luaG_runerror(L, "cannot resume non-suspended coroutine");
+    }
+    /* coroutine is in base level; start running it */
+    if (!luaD_precall(L, rd->firstArg - 1, LUA_MULTRET))  /* Lua function? */
       luaV_execute(L);  /* call it */
       luaV_execute(L);  /* call it */
   }
   }
+  else if (L->status != LUA_YIELD)
+    luaG_runerror(L, "cannot resume dead coroutine");
   else {  /* resuming from previous yield */
   else {  /* resuming from previous yield */
-    lua_assert(L->status == LUA_YIELD);
     L->status = LUA_OK;
     L->status = LUA_OK;
     if (isLua(ci))  /* yielded inside a hook? */
     if (isLua(ci))  /* yielded inside a hook? */
-      luaV_execute(L);
+      luaV_execute(L);  /* just continue running Lua code */
     else {  /* 'common' yield */
     else {  /* 'common' yield */
       if (ci->u.c.k != NULL) {  /* does it have a continuation? */
       if (ci->u.c.k != NULL) {  /* does it have a continuation? */
         int n;
         int n;
@@ -427,25 +446,16 @@ static void resume (lua_State *L, void *ud) {
         n = (*ci->u.c.k)(L);  /* call continuation */
         n = (*ci->u.c.k)(L);  /* call continuation */
         lua_lock(L);
         lua_lock(L);
         api_checknelems(L, n);
         api_checknelems(L, n);
-        firstArg = L->top - n;
+        rd->firstArg = L->top - n;  /* yield results come from continuation */
       }
       }
       G(L)->nCcalls--;  /* finish 'luaD_call' */
       G(L)->nCcalls--;  /* finish 'luaD_call' */
-      luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */
+      luaD_poscall(L, rd->firstArg);  /* finish 'luaD_precall' */
     }
     }
     unroll(L, NULL);
     unroll(L, NULL);
   }
   }
 }
 }
 
 
 
 
-static int resume_error (lua_State *L, const char *msg) {
-  L->top = L->ci->func + 1;
-  setsvalue2s(L, L->top, luaS_new(L, msg));
-  incr_top(L);
-  lua_unlock(L);
-  return LUA_ERRRUN;
-}
-
-
 /*
 /*
 ** check whether thread has a suspended protected call
 ** check whether thread has a suspended protected call
 */
 */
@@ -479,37 +489,34 @@ static int recover (lua_State *L, int status) {
 
 
 
 
 LUA_API int lua_resume (lua_State *L, int nargs) {
 LUA_API int lua_resume (lua_State *L, int nargs) {
+  struct ResumeData rd;
   int status;
   int status;
   lua_lock(L);
   lua_lock(L);
-  if (L->status != LUA_YIELD) {
-    if (L->status != LUA_OK)
-      return resume_error(L, "cannot resume dead coroutine");
-    else if (L->ci != &L->base_ci)
-      return resume_error(L, "cannot resume non-suspended coroutine");
-  }
   luai_userstateresume(L, nargs);
   luai_userstateresume(L, nargs);
-  if (G(L)->nCcalls >= LUAI_MAXCCALLS)
-      return resume_error(L, "C stack overflow");
   ++G(L)->nCcalls;  /* count resume */
   ++G(L)->nCcalls;  /* count resume */
   L->nny = 0;  /* allow yields */
   L->nny = 0;  /* allow yields */
-  status = luaD_rawrunprotected(L, resume, L->top - nargs);
-  while (status != LUA_OK && status != LUA_YIELD) {  /* error? */
-    if (recover(L, status))  /* recover point? */
-      status = luaD_rawrunprotected(L, unroll, NULL);  /* run continuation */
-    else {  /* unrecoverable error */
-      L->status = cast_byte(status);  /* mark thread as `dead' */
-      luaD_seterrorobj(L, status, L->top);
-      L->ci->top = L->top;
-      break;
+  rd.firstArg = L->top - nargs; rd.recover = 1;
+  status = luaD_rawrunprotected(L, resume, &rd);
+  if (rd.recover) {
+    while (status != LUA_OK && status != LUA_YIELD) {  /* error? */
+      if (recover(L, status))  /* recover point? */
+        status = luaD_rawrunprotected(L, unroll, NULL);  /* run continuation */
+      else {  /* unrecoverable error */
+        L->status = cast_byte(status);  /* mark thread as `dead' */
+        luaD_seterrorobj(L, status, L->top);
+        L->ci->top = L->top;
+        break;
+      }
     }
     }
+    lua_assert(status == L->status);
   }
   }
-  lua_assert(status == L->status);
   L->nny = 1;  /* do not allow yields */
   L->nny = 1;  /* do not allow yields */
   --G(L)->nCcalls;
   --G(L)->nCcalls;
   lua_unlock(L);
   lua_unlock(L);
   return status;
   return status;
 }
 }
 
 
+
 LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
 LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
   CallInfo *ci = L->ci;
   CallInfo *ci = L->ci;
   luai_userstateyield(L, nresults);
   luai_userstateyield(L, nresults);