From cf7eff45f3abf2386d5392c0b431498bbb274ac7 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 28 Dec 2017 13:42:57 -0200 Subject: keep control of stack top in Lua functions concentrated in 'luaV_execute' --- lvm.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'lvm.c') diff --git a/lvm.c b/lvm.c index 89646d24..212d5f9d 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.328 2017/12/20 14:58:05 roberto Exp roberto $ +** $Id: lvm.c,v 2.329 2017/12/22 14:16:46 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -464,8 +464,6 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { } if (tm == NULL) /* no TM? */ return 0; /* objects are different */ - if (isLuacode(L->ci)) - L->top = L->ci->top; /* prepare top */ luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ return !l_isfalse(s2v(L->top)); } @@ -780,20 +778,29 @@ void luaV_finishOp (lua_State *L) { #define donextjump(ci) { i = *pc; dojump(ci, i, 1); } /* -** Whenever code can raise errors (including memory errors), the global -** 'pc' must be correct to report occasional errors. +** Correct global 'pc'. */ #define savepc(L) (ci->u.l.savedpc = pc) +/* +** Whenever code can raise errors, the global 'pc' and the global +** 'top' must be correct to report occasional errors. +*/ +#define savestate(L,ci) (savepc(L), L->top = ci->top) + + /* ** Protect code that, in general, can raise errors, reallocate the ** stack, and change the hooks. */ -#define Protect(exp) (savepc(L), (exp), updatetrap(ci)) +#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci)) + +/* special version that does not change the top */ +#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) /* -** Protect code that will return. +** Protect code that will finish the loop (returns). */ #define halfProtect(exp) (savepc(L), (exp)) @@ -842,6 +849,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmfetch(); lua_assert(base == ci->func + 1); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); + lua_assert(ci->top < L->stack + L->stacksize); vmdispatch (GET_OPCODE(i)) { vmcase(OP_MOVE) { setobjs2s(L, ra, RB(i)); @@ -1000,10 +1008,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { int b = GETARG_B(i); int c = GETARG_C(i); Table *t; - t = luaH_new(L); + L->top = ci->top; /* correct top in case of GC */ + t = luaH_new(L); /* memory allocation */ sethvalue2s(L, ra, t); if (b != 0 || c != 0) - luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); /* idem */ checkGC(L, ra + 1); vmbreak; } @@ -1371,7 +1380,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { int c = GETARG_C(i); StkId rb; L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c - b + 1)); + ProtectNT(luaV_concat(L, c - b + 1)); if (trap) { /* 'luaV_concat' may move the stack */ updatebase(ci); ra = RA(i); @@ -1481,7 +1490,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { if (b != 0) /* fixed number of arguments? */ L->top = ra + b; /* top signals number of arguments */ /* else previous instruction set top */ - Protect(luaD_call(L, ra, nresults)); + ProtectNT(luaD_call(L, ra, nresults)); vmbreak; } vmcase(OP_TAILCALL) { @@ -1493,12 +1502,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) { lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); if (!ttisfunction(vra)) { /* not a function? */ /* try to get '__call' metamethod */ - Protect(ra = luaD_tryfuncTM(L, ra)); + ProtectNT(ra = luaD_tryfuncTM(L, ra)); vra = s2v(ra); b++; /* there is now one extra argument */ } if (!ttisLclosure(vra)) { /* C function? */ - Protect(luaD_call(L, ra, LUA_MULTRET)); /* call it */ + ProtectNT(luaD_call(L, ra, LUA_MULTRET)); /* call it */ /* next instruction will do the return */ } else { /* tail call */ @@ -1568,7 +1577,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { lua_Integer ilimit, initv; int stopnow; if (!forlimit(plimit, &ilimit, 1, &stopnow)) { - savepc(L); /* for the error message */ + savestate(L, ci); /* for the error message */ luaG_runerror(L, "'for' limit must be a number"); } initv = (stopnow ? 0 : ivalue(init)); @@ -1618,7 +1627,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { } else { /* try making all values floats */ lua_Number ninit; lua_Number nlimit; lua_Number nstep; - savepc(L); /* in case of errors */ + savestate(L, ci); /* in case of errors */ if (!tonumber(plimit, &nlimit)) luaG_runerror(L, "'for' limit must be a number"); setfltvalue(plimit, nlimit); @@ -1659,7 +1668,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { int c = GETARG_C(i); unsigned int last; Table *h; - if (n == 0) n = cast_int(L->top - ra) - 1; + if (n == 0) + n = cast_int(L->top - ra) - 1; + else + L->top = ci->top; /* correct top in case of GC */ if (c == 0) { c = GETARG_Ax(*pc); pc++; } @@ -1679,7 +1691,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { Proto *p = cl->p->p[GETARG_Bx(i)]; LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) { /* no match? */ - savepc(L); /* in case of allocation errors */ + savestate(L, ci); /* in case of allocation errors */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ } else -- cgit v1.2.3-55-g6feb