diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-27 14:32:29 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-27 14:32:29 -0200 |
| commit | ba7da13ec5938f978c37d63aa40a3e340b301f79 (patch) | |
| tree | c1f22403954f6e0c6d17c8495c11509103313c9a /ldo.c | |
| parent | da37ac9c7894186a0e2e0e6f1f5f00b825fd1555 (diff) | |
| download | lua-ba7da13ec5938f978c37d63aa40a3e340b301f79.tar.gz lua-ba7da13ec5938f978c37d63aa40a3e340b301f79.tar.bz2 lua-ba7da13ec5938f978c37d63aa40a3e340b301f79.zip | |
Changes in the control of C-stack overflow
* unification of the 'nny' and 'nCcalls' counters;
* external C functions ('lua_CFunction') count more "slots" in
the C stack (to allow for their possible use of buffers)
* added a new test script specific for C-stack overflows. (Most
of those tests were already present, but concentrating them
in a single script easies the task of checking whether
'LUAI_MAXCCALLS' is adequate in a system.)
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 40 |
1 files changed, 16 insertions, 24 deletions
| @@ -138,7 +138,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { | |||
| 138 | 138 | ||
| 139 | 139 | ||
| 140 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | 140 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { |
| 141 | unsigned short oldnCcalls = L->nCcalls - L->nci; | 141 | l_uint32 oldnCcalls = L->nCcalls - L->nci; |
| 142 | struct lua_longjmp lj; | 142 | struct lua_longjmp lj; |
| 143 | lua_assert(L->nCcalls >= L->nci); | 143 | lua_assert(L->nCcalls >= L->nci); |
| 144 | lj.status = LUA_OK; | 144 | lj.status = LUA_OK; |
| @@ -513,12 +513,17 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
| 513 | 513 | ||
| 514 | 514 | ||
| 515 | /* | 515 | /* |
| 516 | ** Similar to 'luaD_call', but does not allow yields during the call | 516 | ** Similar to 'luaD_call', but does not allow yields during the call. |
| 517 | ** If there is a stack overflow, freeing all CI structures will | ||
| 518 | ** force the subsequent call to invoke 'luaE_extendCI', which then | ||
| 519 | ** will raise any errors. | ||
| 517 | */ | 520 | */ |
| 518 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { | 521 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { |
| 519 | L->nny++; | 522 | incXCcalls(L); |
| 523 | if (getCcalls(L) >= LUAI_MAXCCALLS) /* possible stack overflow? */ | ||
| 524 | luaE_freeCI(L); | ||
| 520 | luaD_call(L, func, nResults); | 525 | luaD_call(L, func, nResults); |
| 521 | L->nny--; | 526 | decXCcalls(L); |
| 522 | } | 527 | } |
| 523 | 528 | ||
| 524 | 529 | ||
| @@ -530,7 +535,7 @@ static void finishCcall (lua_State *L, int status) { | |||
| 530 | CallInfo *ci = L->ci; | 535 | CallInfo *ci = L->ci; |
| 531 | int n; | 536 | int n; |
| 532 | /* must have a continuation and must be able to call it */ | 537 | /* must have a continuation and must be able to call it */ |
| 533 | lua_assert(ci->u.c.k != NULL && L->nny == 0); | 538 | lua_assert(ci->u.c.k != NULL && yieldable(L)); |
| 534 | /* error status can only happen in a protected call */ | 539 | /* error status can only happen in a protected call */ |
| 535 | lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); | 540 | lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); |
| 536 | if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ | 541 | if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ |
| @@ -601,7 +606,6 @@ static int recover (lua_State *L, int status) { | |||
| 601 | luaD_seterrorobj(L, status, oldtop); | 606 | luaD_seterrorobj(L, status, oldtop); |
| 602 | L->ci = ci; | 607 | L->ci = ci; |
| 603 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ | 608 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ |
| 604 | L->nny = 0; /* should be zero to be yieldable */ | ||
| 605 | luaD_shrinkstack(L); | 609 | luaD_shrinkstack(L); |
| 606 | L->errfunc = ci->u.c.old_errfunc; | 610 | L->errfunc = ci->u.c.old_errfunc; |
| 607 | return 1; /* continue running the coroutine */ | 611 | return 1; /* continue running the coroutine */ |
| @@ -623,13 +627,6 @@ static int resume_error (lua_State *L, const char *msg, int narg) { | |||
| 623 | 627 | ||
| 624 | 628 | ||
| 625 | /* | 629 | /* |
| 626 | ** "Cost" in the C stack for a coroutine invocation. | ||
| 627 | */ | ||
| 628 | #if !defined(LUAL_COROCSTK) | ||
| 629 | #define LUAL_COROCSTK 3 | ||
| 630 | #endif | ||
| 631 | |||
| 632 | /* | ||
| 633 | ** Do the work for 'lua_resume' in protected mode. Most of the work | 630 | ** Do the work for 'lua_resume' in protected mode. Most of the work |
| 634 | ** depends on the status of the coroutine: initial state, suspended | 631 | ** depends on the status of the coroutine: initial state, suspended |
| 635 | ** inside a hook, or regularly suspended (optionally with a continuation | 632 | ** inside a hook, or regularly suspended (optionally with a continuation |
| @@ -664,7 +661,6 @@ static void resume (lua_State *L, void *ud) { | |||
| 664 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | 661 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, |
| 665 | int *nresults) { | 662 | int *nresults) { |
| 666 | int status; | 663 | int status; |
| 667 | unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ | ||
| 668 | lua_lock(L); | 664 | lua_lock(L); |
| 669 | if (L->status == LUA_OK) { /* may be starting a coroutine */ | 665 | if (L->status == LUA_OK) { /* may be starting a coroutine */ |
| 670 | if (L->ci != &L->base_ci) /* not in base level? */ | 666 | if (L->ci != &L->base_ci) /* not in base level? */ |
| @@ -675,11 +671,10 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
| 675 | if (from == NULL) | 671 | if (from == NULL) |
| 676 | L->nCcalls = 1; | 672 | L->nCcalls = 1; |
| 677 | else /* correct 'nCcalls' for this thread */ | 673 | else /* correct 'nCcalls' for this thread */ |
| 678 | L->nCcalls = from->nCcalls - from->nci + L->nci + LUAL_COROCSTK; | 674 | L->nCcalls = getCcalls(from) - from->nci + L->nci + CSTACKCF; |
| 679 | if (L->nCcalls >= LUAI_MAXCCALLS) | 675 | if (L->nCcalls >= LUAI_MAXCCALLS) |
| 680 | return resume_error(L, "C stack overflow", nargs); | 676 | return resume_error(L, "C stack overflow", nargs); |
| 681 | luai_userstateresume(L, nargs); | 677 | luai_userstateresume(L, nargs); |
| 682 | L->nny = 0; /* allow yields */ | ||
| 683 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 678 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
| 684 | status = luaD_rawrunprotected(L, resume, &nargs); | 679 | status = luaD_rawrunprotected(L, resume, &nargs); |
| 685 | /* continue running after recoverable errors */ | 680 | /* continue running after recoverable errors */ |
| @@ -698,14 +693,13 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
| 698 | } | 693 | } |
| 699 | *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield | 694 | *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield |
| 700 | : cast_int(L->top - (L->ci->func + 1)); | 695 | : cast_int(L->top - (L->ci->func + 1)); |
| 701 | L->nny = oldnny; /* restore 'nny' */ | ||
| 702 | lua_unlock(L); | 696 | lua_unlock(L); |
| 703 | return status; | 697 | return status; |
| 704 | } | 698 | } |
| 705 | 699 | ||
| 706 | 700 | ||
| 707 | LUA_API int lua_isyieldable (lua_State *L) { | 701 | LUA_API int lua_isyieldable (lua_State *L) { |
| 708 | return (L->nny == 0); | 702 | return yieldable(L); |
| 709 | } | 703 | } |
| 710 | 704 | ||
| 711 | 705 | ||
| @@ -715,7 +709,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, | |||
| 715 | luai_userstateyield(L, nresults); | 709 | luai_userstateyield(L, nresults); |
| 716 | lua_lock(L); | 710 | lua_lock(L); |
| 717 | api_checknelems(L, nresults); | 711 | api_checknelems(L, nresults); |
| 718 | if (unlikely(L->nny > 0)) { | 712 | if (unlikely(!yieldable(L))) { |
| 719 | if (L != G(L)->mainthread) | 713 | if (L != G(L)->mainthread) |
| 720 | luaG_runerror(L, "attempt to yield across a C-call boundary"); | 714 | luaG_runerror(L, "attempt to yield across a C-call boundary"); |
| 721 | else | 715 | else |
| @@ -741,7 +735,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, | |||
| 741 | 735 | ||
| 742 | /* | 736 | /* |
| 743 | ** Call the C function 'func' in protected mode, restoring basic | 737 | ** Call the C function 'func' in protected mode, restoring basic |
| 744 | ** thread information ('allowhook', 'nny', etc.) and in particular | 738 | ** thread information ('allowhook', etc.) and in particular |
| 745 | ** its stack level in case of errors. | 739 | ** its stack level in case of errors. |
| 746 | */ | 740 | */ |
| 747 | int luaD_pcall (lua_State *L, Pfunc func, void *u, | 741 | int luaD_pcall (lua_State *L, Pfunc func, void *u, |
| @@ -749,7 +743,6 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
| 749 | int status; | 743 | int status; |
| 750 | CallInfo *old_ci = L->ci; | 744 | CallInfo *old_ci = L->ci; |
| 751 | lu_byte old_allowhooks = L->allowhook; | 745 | lu_byte old_allowhooks = L->allowhook; |
| 752 | unsigned short old_nny = L->nny; | ||
| 753 | ptrdiff_t old_errfunc = L->errfunc; | 746 | ptrdiff_t old_errfunc = L->errfunc; |
| 754 | L->errfunc = ef; | 747 | L->errfunc = ef; |
| 755 | status = luaD_rawrunprotected(L, func, u); | 748 | status = luaD_rawrunprotected(L, func, u); |
| @@ -757,7 +750,6 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
| 757 | StkId oldtop = restorestack(L, old_top); | 750 | StkId oldtop = restorestack(L, old_top); |
| 758 | L->ci = old_ci; | 751 | L->ci = old_ci; |
| 759 | L->allowhook = old_allowhooks; | 752 | L->allowhook = old_allowhooks; |
| 760 | L->nny = old_nny; | ||
| 761 | status = luaF_close(L, oldtop, status); | 753 | status = luaF_close(L, oldtop, status); |
| 762 | oldtop = restorestack(L, old_top); /* previous call may change stack */ | 754 | oldtop = restorestack(L, old_top); /* previous call may change stack */ |
| 763 | luaD_seterrorobj(L, status, oldtop); | 755 | luaD_seterrorobj(L, status, oldtop); |
| @@ -811,7 +803,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, | |||
| 811 | const char *mode) { | 803 | const char *mode) { |
| 812 | struct SParser p; | 804 | struct SParser p; |
| 813 | int status; | 805 | int status; |
| 814 | L->nny++; /* cannot yield during parsing */ | 806 | incnny(L); /* cannot yield during parsing */ |
| 815 | p.z = z; p.name = name; p.mode = mode; | 807 | p.z = z; p.name = name; p.mode = mode; |
| 816 | p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; | 808 | p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; |
| 817 | p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; | 809 | p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; |
| @@ -822,7 +814,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, | |||
| 822 | luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); | 814 | luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); |
| 823 | luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); | 815 | luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); |
| 824 | luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); | 816 | luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); |
| 825 | L->nny--; | 817 | decnny(L); |
| 826 | return status; | 818 | return status; |
| 827 | } | 819 | } |
| 828 | 820 | ||
