diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-28 11:40:30 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-28 11:40:30 -0300 |
| commit | 7af27ef59da4051914d93d8b63efac663b64765a (patch) | |
| tree | 73ac919879b442904112dbb972412fc15983d50e /ldo.c | |
| parent | 0ceada8da92135717d31a3954b5b89a954f9e71a (diff) | |
| download | lua-7af27ef59da4051914d93d8b63efac663b64765a.tar.gz lua-7af27ef59da4051914d93d8b63efac663b64765a.tar.bz2 lua-7af27ef59da4051914d93d8b63efac663b64765a.zip | |
Cleaner handling of errors in '__close' metamethods
Instead of protecting each individual metamethod call, protect the
entire call to 'luaF_close'.
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 59 |
1 files changed, 47 insertions, 12 deletions
| @@ -98,11 +98,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { | |||
| 98 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); | 98 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); |
| 99 | break; | 99 | break; |
| 100 | } | 100 | } |
| 101 | case CLOSEPROTECT: { | 101 | case LUA_OK: { /* special case only for closing upvalues */ |
| 102 | setnilvalue(s2v(oldtop)); /* no error message */ | 102 | setnilvalue(s2v(oldtop)); /* no error message */ |
| 103 | break; | 103 | break; |
| 104 | } | 104 | } |
| 105 | default: { | 105 | default: { |
| 106 | lua_assert(errcode >= LUA_ERRRUN); /* real error */ | ||
| 106 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ | 107 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ |
| 107 | break; | 108 | break; |
| 108 | } | 109 | } |
| @@ -118,7 +119,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { | |||
| 118 | } | 119 | } |
| 119 | else { /* thread has no error handler */ | 120 | else { /* thread has no error handler */ |
| 120 | global_State *g = G(L); | 121 | global_State *g = G(L); |
| 121 | errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */ | 122 | errcode = luaD_closeprotected(L, 0, errcode); /* close all upvalues */ |
| 122 | L->status = cast_byte(errcode); /* mark it as dead */ | 123 | L->status = cast_byte(errcode); /* mark it as dead */ |
| 123 | if (g->mainthread->errorJmp) { /* main thread has a handler? */ | 124 | if (g->mainthread->errorJmp) { /* main thread has a handler? */ |
| 124 | setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ | 125 | setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ |
| @@ -409,7 +410,7 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) { | |||
| 409 | default: /* multiple results (or to-be-closed variables) */ | 410 | default: /* multiple results (or to-be-closed variables) */ |
| 410 | if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ | 411 | if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ |
| 411 | ptrdiff_t savedres = savestack(L, res); | 412 | ptrdiff_t savedres = savestack(L, res); |
| 412 | luaF_close(L, res, LUA_OK); /* may change the stack */ | 413 | luaF_close(L, res, CLOSEKTOP); /* may change the stack */ |
| 413 | res = restorestack(L, savedres); | 414 | res = restorestack(L, savedres); |
| 414 | wanted = codeNresults(wanted); /* correct value */ | 415 | wanted = codeNresults(wanted); /* correct value */ |
| 415 | if (wanted == LUA_MULTRET) | 416 | if (wanted == LUA_MULTRET) |
| @@ -636,16 +637,13 @@ static CallInfo *findpcall (lua_State *L) { | |||
| 636 | ** 'luaD_pcall'. If there is no recover point, returns zero. | 637 | ** 'luaD_pcall'. If there is no recover point, returns zero. |
| 637 | */ | 638 | */ |
| 638 | static int recover (lua_State *L, int status) { | 639 | static int recover (lua_State *L, int status) { |
| 639 | StkId oldtop; | ||
| 640 | CallInfo *ci = findpcall(L); | 640 | CallInfo *ci = findpcall(L); |
| 641 | if (ci == NULL) return 0; /* no recovery point */ | 641 | if (ci == NULL) return 0; /* no recovery point */ |
| 642 | /* "finish" luaD_pcall */ | 642 | /* "finish" luaD_pcall */ |
| 643 | oldtop = restorestack(L, ci->u2.funcidx); | ||
| 644 | L->ci = ci; | 643 | L->ci = ci; |
| 645 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ | 644 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ |
| 646 | status = luaF_close(L, oldtop, status); /* may change the stack */ | 645 | status = luaD_closeprotected(L, ci->u2.funcidx, status); |
| 647 | oldtop = restorestack(L, ci->u2.funcidx); | 646 | luaD_seterrorobj(L, status, restorestack(L, ci->u2.funcidx)); |
| 648 | luaD_seterrorobj(L, status, oldtop); | ||
| 649 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | 647 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
| 650 | L->errfunc = ci->u.c.old_errfunc; | 648 | L->errfunc = ci->u.c.old_errfunc; |
| 651 | return 1; /* continue running the coroutine */ | 649 | return 1; /* continue running the coroutine */ |
| @@ -770,6 +768,45 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, | |||
| 770 | 768 | ||
| 771 | 769 | ||
| 772 | /* | 770 | /* |
| 771 | ** Auxiliary structure to call 'luaF_close' in protected mode. | ||
| 772 | */ | ||
| 773 | struct CloseP { | ||
| 774 | StkId level; | ||
| 775 | int status; | ||
| 776 | }; | ||
| 777 | |||
| 778 | |||
| 779 | /* | ||
| 780 | ** Auxiliary function to call 'luaF_close' in protected mode. | ||
| 781 | */ | ||
| 782 | static void closepaux (lua_State *L, void *ud) { | ||
| 783 | struct CloseP *pcl = cast(struct CloseP *, ud); | ||
| 784 | luaF_close(L, pcl->level, pcl->status); | ||
| 785 | } | ||
| 786 | |||
| 787 | |||
| 788 | /* | ||
| 789 | ** Calls 'luaF_close' in protected mode. Return the original status | ||
| 790 | ** or, in case of errors, the new status. | ||
| 791 | */ | ||
| 792 | int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) { | ||
| 793 | CallInfo *old_ci = L->ci; | ||
| 794 | lu_byte old_allowhooks = L->allowhook; | ||
| 795 | for (;;) { /* keep closing upvalues until no more errors */ | ||
| 796 | struct CloseP pcl; | ||
| 797 | pcl.level = restorestack(L, level); pcl.status = status; | ||
| 798 | status = luaD_rawrunprotected(L, &closepaux, &pcl); | ||
| 799 | if (likely(status == LUA_OK)) /* no more errors? */ | ||
| 800 | return pcl.status; | ||
| 801 | else { /* an error occurred; restore saved state and repeat */ | ||
| 802 | L->ci = old_ci; | ||
| 803 | L->allowhook = old_allowhooks; | ||
| 804 | } | ||
| 805 | } | ||
| 806 | } | ||
| 807 | |||
| 808 | |||
| 809 | /* | ||
| 773 | ** Call the C function 'func' in protected mode, restoring basic | 810 | ** Call the C function 'func' in protected mode, restoring basic |
| 774 | ** thread information ('allowhook', etc.) and in particular | 811 | ** thread information ('allowhook', etc.) and in particular |
| 775 | ** its stack level in case of errors. | 812 | ** its stack level in case of errors. |
| @@ -783,12 +820,10 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
| 783 | L->errfunc = ef; | 820 | L->errfunc = ef; |
| 784 | status = luaD_rawrunprotected(L, func, u); | 821 | status = luaD_rawrunprotected(L, func, u); |
| 785 | if (unlikely(status != LUA_OK)) { /* an error occurred? */ | 822 | if (unlikely(status != LUA_OK)) { /* an error occurred? */ |
| 786 | StkId oldtop = restorestack(L, old_top); | ||
| 787 | L->ci = old_ci; | 823 | L->ci = old_ci; |
| 788 | L->allowhook = old_allowhooks; | 824 | L->allowhook = old_allowhooks; |
| 789 | status = luaF_close(L, oldtop, status); | 825 | status = luaD_closeprotected(L, old_top, status); |
| 790 | oldtop = restorestack(L, old_top); /* previous call may change stack */ | 826 | luaD_seterrorobj(L, status, restorestack(L, old_top)); |
| 791 | luaD_seterrorobj(L, status, oldtop); | ||
| 792 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | 827 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
| 793 | } | 828 | } |
| 794 | L->errfunc = old_errfunc; | 829 | L->errfunc = old_errfunc; |
