diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-07-07 18:03:48 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-07-07 18:03:48 -0300 |
| commit | eb41999461b6f428186c55abd95f4ce1a76217d5 (patch) | |
| tree | 577e56c4ad5999b34966232b1e2a2bf9a63f7cc2 | |
| parent | 314c6057b785cd94ac88905ccfce61724107d66b (diff) | |
| download | lua-eb41999461b6f428186c55abd95f4ce1a76217d5.tar.gz lua-eb41999461b6f428186c55abd95f4ce1a76217d5.tar.bz2 lua-eb41999461b6f428186c55abd95f4ce1a76217d5.zip | |
Fixed bugs of stack reallocation x GC
Macro 'checkstackGC' was doing a GC step after resizing the stack;
the GC could shrink the stack and undo the resize. Moreover, macro
'checkstackp' also does a GC step, which could remove the preallocated
CallInfo when calling a function. (Its name has been changed to
'checkstackGCp' to emphasize that it calls the GC.)
| -rw-r--r-- | ldo.c | 13 | ||||
| -rw-r--r-- | ldo.h | 6 | ||||
| -rw-r--r-- | ltm.c | 4 | ||||
| -rw-r--r-- | lvm.c | 2 |
4 files changed, 14 insertions, 11 deletions
| @@ -465,13 +465,13 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
| 465 | f = fvalue(s2v(func)); | 465 | f = fvalue(s2v(func)); |
| 466 | Cfunc: { | 466 | Cfunc: { |
| 467 | int n; /* number of returns */ | 467 | int n; /* number of returns */ |
| 468 | CallInfo *ci = next_ci(L); | 468 | CallInfo *ci; |
| 469 | checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ | 469 | checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ |
| 470 | L->ci = ci = next_ci(L); | ||
| 470 | ci->nresults = nresults; | 471 | ci->nresults = nresults; |
| 471 | ci->callstatus = CIST_C; | 472 | ci->callstatus = CIST_C; |
| 472 | ci->top = L->top + LUA_MINSTACK; | 473 | ci->top = L->top + LUA_MINSTACK; |
| 473 | ci->func = func; | 474 | ci->func = func; |
| 474 | L->ci = ci; | ||
| 475 | lua_assert(ci->top <= L->stack_last); | 475 | lua_assert(ci->top <= L->stack_last); |
| 476 | if (L->hookmask & LUA_MASKCALL) { | 476 | if (L->hookmask & LUA_MASKCALL) { |
| 477 | int narg = cast_int(L->top - func) - 1; | 477 | int narg = cast_int(L->top - func) - 1; |
| @@ -485,12 +485,13 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
| 485 | break; | 485 | break; |
| 486 | } | 486 | } |
| 487 | case LUA_VLCL: { /* Lua function */ | 487 | case LUA_VLCL: { /* Lua function */ |
| 488 | CallInfo *ci = next_ci(L); | 488 | CallInfo *ci; |
| 489 | Proto *p = clLvalue(s2v(func))->p; | 489 | Proto *p = clLvalue(s2v(func))->p; |
| 490 | int narg = cast_int(L->top - func) - 1; /* number of real arguments */ | 490 | int narg = cast_int(L->top - func) - 1; /* number of real arguments */ |
| 491 | int nfixparams = p->numparams; | 491 | int nfixparams = p->numparams; |
| 492 | int fsize = p->maxstacksize; /* frame size */ | 492 | int fsize = p->maxstacksize; /* frame size */ |
| 493 | checkstackp(L, fsize, func); | 493 | checkstackGCp(L, fsize, func); |
| 494 | L->ci = ci = next_ci(L); | ||
| 494 | ci->nresults = nresults; | 495 | ci->nresults = nresults; |
| 495 | ci->u.l.savedpc = p->code; /* starting point */ | 496 | ci->u.l.savedpc = p->code; /* starting point */ |
| 496 | ci->callstatus = 0; | 497 | ci->callstatus = 0; |
| @@ -504,7 +505,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
| 504 | break; | 505 | break; |
| 505 | } | 506 | } |
| 506 | default: { /* not a function */ | 507 | default: { /* not a function */ |
| 507 | checkstackp(L, 1, func); /* space for metamethod */ | 508 | checkstackGCp(L, 1, func); /* space for metamethod */ |
| 508 | luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ | 509 | luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ |
| 509 | goto retry; /* try again with metamethod */ | 510 | goto retry; /* try again with metamethod */ |
| 510 | } | 511 | } |
| @@ -17,6 +17,8 @@ | |||
| 17 | ** Macro to check stack size and grow stack if needed. Parameters | 17 | ** Macro to check stack size and grow stack if needed. Parameters |
| 18 | ** 'pre'/'pos' allow the macro to preserve a pointer into the | 18 | ** 'pre'/'pos' allow the macro to preserve a pointer into the |
| 19 | ** stack across reallocations, doing the work only when needed. | 19 | ** stack across reallocations, doing the work only when needed. |
| 20 | ** It also allows the running of one GC step when the stack is | ||
| 21 | ** reallocated. | ||
| 20 | ** 'condmovestack' is used in heavy tests to force a stack reallocation | 22 | ** 'condmovestack' is used in heavy tests to force a stack reallocation |
| 21 | ** at every check. | 23 | ** at every check. |
| 22 | */ | 24 | */ |
| @@ -35,7 +37,7 @@ | |||
| 35 | 37 | ||
| 36 | 38 | ||
| 37 | /* macro to check stack size, preserving 'p' */ | 39 | /* macro to check stack size, preserving 'p' */ |
| 38 | #define checkstackp(L,n,p) \ | 40 | #define checkstackGCp(L,n,p) \ |
| 39 | luaD_checkstackaux(L, n, \ | 41 | luaD_checkstackaux(L, n, \ |
| 40 | ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ | 42 | ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ |
| 41 | luaC_checkGC(L), /* stack grow uses memory */ \ | 43 | luaC_checkGC(L), /* stack grow uses memory */ \ |
| @@ -44,7 +46,7 @@ | |||
| 44 | 46 | ||
| 45 | /* macro to check stack size and GC */ | 47 | /* macro to check stack size and GC */ |
| 46 | #define checkstackGC(L,fsize) \ | 48 | #define checkstackGC(L,fsize) \ |
| 47 | luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L)) | 49 | luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) |
| 48 | 50 | ||
| 49 | 51 | ||
| 50 | /* type of protected functions, to be ran by 'runprotected' */ | 52 | /* type of protected functions, to be ran by 'runprotected' */ |
| @@ -240,7 +240,7 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, | |||
| 240 | int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */ | 240 | int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */ |
| 241 | int nextra = actual - nfixparams; /* number of extra arguments */ | 241 | int nextra = actual - nfixparams; /* number of extra arguments */ |
| 242 | ci->u.l.nextraargs = nextra; | 242 | ci->u.l.nextraargs = nextra; |
| 243 | checkstackGC(L, p->maxstacksize + 1); | 243 | luaD_checkstack(L, p->maxstacksize + 1); |
| 244 | /* copy function to the top of the stack */ | 244 | /* copy function to the top of the stack */ |
| 245 | setobjs2s(L, L->top++, ci->func); | 245 | setobjs2s(L, L->top++, ci->func); |
| 246 | /* move fixed parameters to the top of the stack */ | 246 | /* move fixed parameters to the top of the stack */ |
| @@ -259,7 +259,7 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { | |||
| 259 | int nextra = ci->u.l.nextraargs; | 259 | int nextra = ci->u.l.nextraargs; |
| 260 | if (wanted < 0) { | 260 | if (wanted < 0) { |
| 261 | wanted = nextra; /* get all extra arguments available */ | 261 | wanted = nextra; /* get all extra arguments available */ |
| 262 | checkstackp(L, nextra, where); /* ensure stack space */ | 262 | checkstackGCp(L, nextra, where); /* ensure stack space */ |
| 263 | L->top = where + nextra; /* next instruction will need top */ | 263 | L->top = where + nextra; /* next instruction will need top */ |
| 264 | } | 264 | } |
| 265 | for (i = 0; i < wanted && i < nextra; i++) | 265 | for (i = 0; i < wanted && i < nextra; i++) |
| @@ -1634,7 +1634,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1634 | while (!ttisfunction(s2v(ra))) { /* not a function? */ | 1634 | while (!ttisfunction(s2v(ra))) { /* not a function? */ |
| 1635 | luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ | 1635 | luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ |
| 1636 | b++; /* there is now one extra argument */ | 1636 | b++; /* there is now one extra argument */ |
| 1637 | checkstackp(L, 1, ra); | 1637 | checkstackGCp(L, 1, ra); |
| 1638 | } | 1638 | } |
| 1639 | if (!ttisLclosure(s2v(ra))) { /* C function? */ | 1639 | if (!ttisLclosure(s2v(ra))) { /* C function? */ |
| 1640 | luaD_call(L, ra, LUA_MULTRET); /* call it */ | 1640 | luaD_call(L, ra, LUA_MULTRET); /* call it */ |
