diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-07-29 14:12:44 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-07-29 14:12:44 -0300 |
commit | 9de2bb0d62a2531c47e5b8197f57a48c9aea05d2 (patch) | |
tree | 6af79a00aeda8ad7ec0cbc7686341fa2ac079a6a | |
parent | d55fd3455ba4672feac5b2f85bc35af0aab57ced (diff) | |
download | lua-9de2bb0d62a2531c47e5b8197f57a48c9aea05d2.tar.gz lua-9de2bb0d62a2531c47e5b8197f57a48c9aea05d2.tar.bz2 lua-9de2bb0d62a2531c47e5b8197f57a48c9aea05d2.zip |
bug: When a coroutine tries to resume a non-suspended coroutine,
it coud do some mess (and break C assertions) before detecting the error.
Now it tests for those errors before anything else.
-rw-r--r-- | ldo.c | 35 |
1 files changed, 19 insertions, 16 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldo.c,v 2.150 2015/11/19 19:16:22 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp roberto $ |
3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -595,15 +595,16 @@ static int recover (lua_State *L, int status) { | |||
595 | 595 | ||
596 | 596 | ||
597 | /* | 597 | /* |
598 | ** signal an error in the call to 'resume', not in the execution of the | 598 | ** Signal an error in the call to 'lua_resume', not in the execution |
599 | ** coroutine itself. (Such errors should not be handled by any coroutine | 599 | ** of the coroutine itself. (Such errors should not be handled by any |
600 | ** error handler and should not kill the coroutine.) | 600 | ** coroutine error handler and should not kill the coroutine.) |
601 | */ | 601 | */ |
602 | static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { | 602 | static int resume_error (lua_State *L, const char *msg, int narg) { |
603 | L->top = firstArg; /* remove args from the stack */ | 603 | L->top -= narg; /* remove args from the stack */ |
604 | setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ | 604 | setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ |
605 | api_incr_top(L); | 605 | api_incr_top(L); |
606 | luaD_throw(L, -1); /* jump back to 'lua_resume' */ | 606 | lua_unlock(L); |
607 | return LUA_ERRRUN; | ||
607 | } | 608 | } |
608 | 609 | ||
609 | 610 | ||
@@ -619,18 +620,12 @@ static void resume (lua_State *L, void *ud) { | |||
619 | int n = *(cast(int*, ud)); /* number of arguments */ | 620 | int n = *(cast(int*, ud)); /* number of arguments */ |
620 | StkId firstArg = L->top - n; /* first argument */ | 621 | StkId firstArg = L->top - n; /* first argument */ |
621 | CallInfo *ci = L->ci; | 622 | CallInfo *ci = L->ci; |
622 | if (nCcalls >= LUAI_MAXCCALLS) | 623 | if (L->status == LUA_OK) { /* starting a coroutine? */ |
623 | resume_error(L, "C stack overflow", firstArg); | ||
624 | if (L->status == LUA_OK) { /* may be starting a coroutine */ | ||
625 | if (ci != &L->base_ci) /* not in base level? */ | ||
626 | resume_error(L, "cannot resume non-suspended coroutine", firstArg); | ||
627 | /* coroutine is in base level; start running it */ | ||
628 | if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ | 624 | if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ |
629 | luaV_execute(L); /* call it */ | 625 | luaV_execute(L); /* call it */ |
630 | } | 626 | } |
631 | else if (L->status != LUA_YIELD) | ||
632 | resume_error(L, "cannot resume dead coroutine", firstArg); | ||
633 | else { /* resuming from previous yield */ | 627 | else { /* resuming from previous yield */ |
628 | lua_assert(L->status == LUA_YIELD); | ||
634 | L->status = LUA_OK; /* mark that it is running (again) */ | 629 | L->status = LUA_OK; /* mark that it is running (again) */ |
635 | ci->func = restorestack(L, ci->extra); | 630 | ci->func = restorestack(L, ci->extra); |
636 | if (isLua(ci)) /* yielded inside a hook? */ | 631 | if (isLua(ci)) /* yielded inside a hook? */ |
@@ -655,8 +650,16 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { | |||
655 | int status; | 650 | int status; |
656 | unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ | 651 | unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ |
657 | lua_lock(L); | 652 | lua_lock(L); |
658 | luai_userstateresume(L, nargs); | 653 | if (L->status == LUA_OK) { /* may be starting a coroutine */ |
654 | if (L->ci != &L->base_ci) /* not in base level? */ | ||
655 | return resume_error(L, "cannot resume non-suspended coroutine", nargs); | ||
656 | } | ||
657 | else if (L->status != LUA_YIELD) | ||
658 | return resume_error(L, "cannot resume dead coroutine", nargs); | ||
659 | L->nCcalls = (from) ? from->nCcalls + 1 : 1; | 659 | L->nCcalls = (from) ? from->nCcalls + 1 : 1; |
660 | if (L->nCcalls >= LUAI_MAXCCALLS) | ||
661 | return resume_error(L, "C stack overflow", nargs); | ||
662 | luai_userstateresume(L, nargs); | ||
660 | L->nny = 0; /* allow yields */ | 663 | L->nny = 0; /* allow yields */ |
661 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 664 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
662 | status = luaD_rawrunprotected(L, resume, &nargs); | 665 | status = luaD_rawrunprotected(L, resume, &nargs); |