diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-12-08 16:59:24 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-12-08 16:59:24 -0200 |
| commit | 2643da67c686bac5e29fdf94f54a06e33eb08dd0 (patch) | |
| tree | 20e934b3096eece9f8f337fd572768327924b05e | |
| parent | ed117bb42afc67c83c677347842b35f1ebd51877 (diff) | |
| download | lua-2643da67c686bac5e29fdf94f54a06e33eb08dd0.tar.gz lua-2643da67c686bac5e29fdf94f54a06e33eb08dd0.tar.bz2 lua-2643da67c686bac5e29fdf94f54a06e33eb08dd0.zip | |
error messages from 'lua_resume' must be generated in protected mode,
to avoid raising memory errors
| -rw-r--r-- | ldo.c | 79 |
1 files changed, 43 insertions, 36 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.c,v 2.73 2009/11/25 15:27:51 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.74 2009/11/27 15:37:59 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 | */ |
| @@ -404,19 +404,38 @@ static void unroll (lua_State *L, void *ud) { | |||
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | 406 | ||
| 407 | /* | ||
| 408 | ** data to be passed to 'resume' by 'lua_resume' | ||
| 409 | */ | ||
| 410 | struct ResumeData { | ||
| 411 | StkId firstArg; /* stack index of first argument */ | ||
| 412 | int recover; /* should try to recover in case of errors */ | ||
| 413 | }; | ||
| 414 | |||
| 415 | |||
| 416 | /* | ||
| 417 | ** do the work for 'lua_resume' in protected mode | ||
| 418 | */ | ||
| 407 | static void resume (lua_State *L, void *ud) { | 419 | static void resume (lua_State *L, void *ud) { |
| 408 | StkId firstArg = cast(StkId, ud); | 420 | struct ResumeData *rd = cast(struct ResumeData *, ud); |
| 409 | CallInfo *ci = L->ci; | 421 | CallInfo *ci = L->ci; |
| 410 | if (L->status == LUA_OK) { /* start coroutine? */ | 422 | if (G(L)->nCcalls >= LUAI_MAXCCALLS) |
| 411 | lua_assert(ci == &L->base_ci); | 423 | luaG_runerror(L, "C stack overflow"); |
| 412 | if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ | 424 | if (L->status == LUA_OK) { /* may be starting a coroutine */ |
| 425 | if (ci != &L->base_ci) { /* not in base level? */ | ||
| 426 | rd->recover = 0; /* thread may not be running as a coroutine */ | ||
| 427 | luaG_runerror(L, "cannot resume non-suspended coroutine"); | ||
| 428 | } | ||
| 429 | /* coroutine is in base level; start running it */ | ||
| 430 | if (!luaD_precall(L, rd->firstArg - 1, LUA_MULTRET)) /* Lua function? */ | ||
| 413 | luaV_execute(L); /* call it */ | 431 | luaV_execute(L); /* call it */ |
| 414 | } | 432 | } |
| 433 | else if (L->status != LUA_YIELD) | ||
| 434 | luaG_runerror(L, "cannot resume dead coroutine"); | ||
| 415 | else { /* resuming from previous yield */ | 435 | else { /* resuming from previous yield */ |
| 416 | lua_assert(L->status == LUA_YIELD); | ||
| 417 | L->status = LUA_OK; | 436 | L->status = LUA_OK; |
| 418 | if (isLua(ci)) /* yielded inside a hook? */ | 437 | if (isLua(ci)) /* yielded inside a hook? */ |
| 419 | luaV_execute(L); | 438 | luaV_execute(L); /* just continue running Lua code */ |
| 420 | else { /* 'common' yield */ | 439 | else { /* 'common' yield */ |
| 421 | if (ci->u.c.k != NULL) { /* does it have a continuation? */ | 440 | if (ci->u.c.k != NULL) { /* does it have a continuation? */ |
| 422 | int n; | 441 | int n; |
| @@ -427,25 +446,16 @@ static void resume (lua_State *L, void *ud) { | |||
| 427 | n = (*ci->u.c.k)(L); /* call continuation */ | 446 | n = (*ci->u.c.k)(L); /* call continuation */ |
| 428 | lua_lock(L); | 447 | lua_lock(L); |
| 429 | api_checknelems(L, n); | 448 | api_checknelems(L, n); |
| 430 | firstArg = L->top - n; | 449 | rd->firstArg = L->top - n; /* yield results come from continuation */ |
| 431 | } | 450 | } |
| 432 | G(L)->nCcalls--; /* finish 'luaD_call' */ | 451 | G(L)->nCcalls--; /* finish 'luaD_call' */ |
| 433 | luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ | 452 | luaD_poscall(L, rd->firstArg); /* finish 'luaD_precall' */ |
| 434 | } | 453 | } |
| 435 | unroll(L, NULL); | 454 | unroll(L, NULL); |
| 436 | } | 455 | } |
| 437 | } | 456 | } |
| 438 | 457 | ||
| 439 | 458 | ||
| 440 | static int resume_error (lua_State *L, const char *msg) { | ||
| 441 | L->top = L->ci->func + 1; | ||
| 442 | setsvalue2s(L, L->top, luaS_new(L, msg)); | ||
| 443 | incr_top(L); | ||
| 444 | lua_unlock(L); | ||
| 445 | return LUA_ERRRUN; | ||
| 446 | } | ||
| 447 | |||
| 448 | |||
| 449 | /* | 459 | /* |
| 450 | ** check whether thread has a suspended protected call | 460 | ** check whether thread has a suspended protected call |
| 451 | */ | 461 | */ |
| @@ -479,37 +489,34 @@ static int recover (lua_State *L, int status) { | |||
| 479 | 489 | ||
| 480 | 490 | ||
| 481 | LUA_API int lua_resume (lua_State *L, int nargs) { | 491 | LUA_API int lua_resume (lua_State *L, int nargs) { |
| 492 | struct ResumeData rd; | ||
| 482 | int status; | 493 | int status; |
| 483 | lua_lock(L); | 494 | lua_lock(L); |
| 484 | if (L->status != LUA_YIELD) { | ||
| 485 | if (L->status != LUA_OK) | ||
| 486 | return resume_error(L, "cannot resume dead coroutine"); | ||
| 487 | else if (L->ci != &L->base_ci) | ||
| 488 | return resume_error(L, "cannot resume non-suspended coroutine"); | ||
| 489 | } | ||
| 490 | luai_userstateresume(L, nargs); | 495 | luai_userstateresume(L, nargs); |
| 491 | if (G(L)->nCcalls >= LUAI_MAXCCALLS) | ||
| 492 | return resume_error(L, "C stack overflow"); | ||
| 493 | ++G(L)->nCcalls; /* count resume */ | 496 | ++G(L)->nCcalls; /* count resume */ |
| 494 | L->nny = 0; /* allow yields */ | 497 | L->nny = 0; /* allow yields */ |
| 495 | status = luaD_rawrunprotected(L, resume, L->top - nargs); | 498 | rd.firstArg = L->top - nargs; rd.recover = 1; |
| 496 | while (status != LUA_OK && status != LUA_YIELD) { /* error? */ | 499 | status = luaD_rawrunprotected(L, resume, &rd); |
| 497 | if (recover(L, status)) /* recover point? */ | 500 | if (rd.recover) { |
| 498 | status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */ | 501 | while (status != LUA_OK && status != LUA_YIELD) { /* error? */ |
| 499 | else { /* unrecoverable error */ | 502 | if (recover(L, status)) /* recover point? */ |
| 500 | L->status = cast_byte(status); /* mark thread as `dead' */ | 503 | status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */ |
| 501 | luaD_seterrorobj(L, status, L->top); | 504 | else { /* unrecoverable error */ |
| 502 | L->ci->top = L->top; | 505 | L->status = cast_byte(status); /* mark thread as `dead' */ |
| 503 | break; | 506 | luaD_seterrorobj(L, status, L->top); |
| 507 | L->ci->top = L->top; | ||
| 508 | break; | ||
| 509 | } | ||
| 504 | } | 510 | } |
| 511 | lua_assert(status == L->status); | ||
| 505 | } | 512 | } |
| 506 | lua_assert(status == L->status); | ||
| 507 | L->nny = 1; /* do not allow yields */ | 513 | L->nny = 1; /* do not allow yields */ |
| 508 | --G(L)->nCcalls; | 514 | --G(L)->nCcalls; |
| 509 | lua_unlock(L); | 515 | lua_unlock(L); |
| 510 | return status; | 516 | return status; |
| 511 | } | 517 | } |
| 512 | 518 | ||
| 519 | |||
| 513 | LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { | 520 | LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { |
| 514 | CallInfo *ci = L->ci; | 521 | CallInfo *ci = L->ci; |
| 515 | luai_userstateyield(L, nresults); | 522 | luai_userstateyield(L, nresults); |
