Bläddra i källkod

Avoid setting the stack top below upvalues to be closed

When leaving a scope, the new stack top should be set only after
closing any upvalue, to avoid manipulating values in an "invalid"
part of the stack.
Roberto Ierusalimschy 6 år sedan
förälder
incheckning
298f383ffc
3 ändrade filer med 13 tillägg och 9 borttagningar
  1. 8 7
      lapi.c
  2. 1 0
      lfunc.c
  3. 4 2
      lvm.c

+ 8 - 7
lapi.c

@@ -171,19 +171,20 @@ LUA_API int lua_gettop (lua_State *L) {
 
 LUA_API void lua_settop (lua_State *L, int idx) {
   StkId func = L->ci->func;
+  int diff;  /* difference for new top */
   lua_lock(L);
   if (idx >= 0) {
-    StkId newtop = (func + 1) + idx;
-    api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
-    while (L->top < newtop)
-      setnilvalue(s2v(L->top++));
-    L->top = newtop;
+    api_check(L, idx <= L->ci->top - (func + 1), "new top too large");
+    diff = (func + 1) + idx - L->top;
+    for (; diff > 0; diff--)
+      setnilvalue(s2v(L->top++));  /* clear new slots */
   }
   else {
     api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
-    L->top += idx+1;  /* 'subtract' index (index is negative) */
+    diff = idx + 1;  /* will "subtract" index (as it is negative) */
   }
-  luaF_close(L, L->top, LUA_OK);
+  luaF_close(L, L->top + diff, LUA_OK);
+  L->top += diff;  /* correct top only after closing any upvalue */
   lua_unlock(L);
 }
 

+ 1 - 0
lfunc.c

@@ -202,6 +202,7 @@ int luaF_close (lua_State *L, StkId level, int status) {
   while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
     StkId upl = uplevel(uv);
     TValue *slot = &uv->u.value;  /* new position for value */
+    lua_assert(upl < L->top);
     luaF_unlinkupval(uv);
     setobj(L, slot, uv->v);  /* move value to upvalue slot */
     uv->v = slot;  /* now current value lives here */

+ 4 - 2
lvm.c

@@ -1601,15 +1601,17 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         int n = GETARG_B(i) - 1;  /* number of results */
         if (n < 0)  /* not fixed? */
           n = cast_int(L->top - ra);  /* get what is available */
-        else
-          L->top = ra + n;  /* set call for 'luaD_poscall' */
         savepc(ci);
         if (TESTARG_k(i)) {
           int nparams1 = GETARG_C(i);
+          if (L->top < ci->top)
+            L->top = ci->top;
           luaF_close(L, base, LUA_OK);  /* there may be open upvalues */
+          updatestack(ci);
           if (nparams1)  /* vararg function? */
             ci->func -= ci->u.l.nextraargs + nparams1;
         }
+        L->top = ra + n;  /* set call for 'luaD_poscall' */
         luaD_poscall(L, ci, n);
         return;
       }