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 /ldo.c | |
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
Diffstat (limited to 'ldo.c')
-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); |