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); |
