Browse Source

Small bug with stack reallocation

OP_RETURN must update trap before updating stack. (Bug detected with
-DHARDSTACKTESTS). Also, in 'luaF_close', do not create a variable
with 'uplevel(uv)', as the stack may change and invalidate this
value. (This is not a bug, but could become one if 'upl' was used
again.)
Roberto Ierusalimschy 6 years ago
parent
commit
024a6071ca
2 changed files with 9 additions and 7 deletions
  1. 3 4
      lfunc.c
  2. 6 3
      lvm.c

+ 3 - 4
lfunc.c

@@ -202,13 +202,12 @@ void luaF_unlinkupval (UpVal *uv) {
 int luaF_close (lua_State *L, StkId level, int status) {
 int luaF_close (lua_State *L, StkId level, int status) {
   UpVal *uv;
   UpVal *uv;
   while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
   while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
-    StkId upl = uplevel(uv);
     TValue *slot = &uv->u.value;  /* new position for value */
     TValue *slot = &uv->u.value;  /* new position for value */
-    lua_assert(upl < L->top);
+    lua_assert(uplevel(uv) < L->top);
     if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) {
     if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) {
-      /* must run closing method */
+      /* must run closing method, which may change the stack */
       ptrdiff_t levelrel = savestack(L, level);
       ptrdiff_t levelrel = savestack(L, level);
-      status = callclosemth(L, upl, status);  /* may change the stack */
+      status = callclosemth(L, uplevel(uv), status);
       level = restorestack(L, levelrel);
       level = restorestack(L, levelrel);
     }
     }
     luaF_unlinkupval(uv);
     luaF_unlinkupval(uv);

+ 6 - 3
lvm.c

@@ -1574,8 +1574,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         savepc(ci);  /* some calls here can raise errors */
         savepc(ci);  /* some calls here can raise errors */
         if (TESTARG_k(i)) {
         if (TESTARG_k(i)) {
           /* close upvalues from current call; the compiler ensures
           /* close upvalues from current call; the compiler ensures
-             that there are no to-be-closed variables here */
+             that there are no to-be-closed variables here, so this
+             call cannot change the stack */
           luaF_close(L, base, NOCLOSINGMETH);
           luaF_close(L, base, NOCLOSINGMETH);
+          lua_assert(base == ci->func + 1);
         }
         }
         if (!ttisfunction(s2v(ra))) {  /* not a function? */
         if (!ttisfunction(s2v(ra))) {  /* not a function? */
           luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */
           luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */
@@ -1602,10 +1604,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         if (n < 0)  /* not fixed? */
         if (n < 0)  /* not fixed? */
           n = cast_int(L->top - ra);  /* get what is available */
           n = cast_int(L->top - ra);  /* get what is available */
         savepc(ci);
         savepc(ci);
-        if (TESTARG_k(i)) {
+        if (TESTARG_k(i)) {  /* may there be open upvalues? */
           if (L->top < ci->top)
           if (L->top < ci->top)
             L->top = ci->top;
             L->top = ci->top;
-          luaF_close(L, base, LUA_OK);  /* there may be open upvalues */
+          luaF_close(L, base, LUA_OK);
+          updatetrap(ci);
           updatestack(ci);
           updatestack(ci);
         }
         }
         if (nparams1)  /* vararg function? */
         if (nparams1)  /* vararg function? */