浏览代码

Avoid out-of-range PC for stack overflow error from snapshot restore.

Reported by Sergey Kaplun. #1359
Mike Pall 3 月之前
父节点
当前提交
cd4af8ad80
共有 3 个文件被更改,包括 10 次插入15 次删除
  1. 5 0
      src/lj_bc.h
  2. 1 13
      src/lj_parse.c
  3. 4 2
      src/lj_snap.c

+ 5 - 0
src/lj_bc.h

@@ -255,6 +255,11 @@ static LJ_AINLINE int bc_isret(BCOp op)
   return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
   return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
 }
 }
 
 
+static LJ_AINLINE int bc_isret_or_tail(BCOp op)
+{
+  return (op == BC_CALLMT || op == BC_CALLT || bc_isret(op));
+}
+
 LJ_DATA const uint16_t lj_bc_mode[];
 LJ_DATA const uint16_t lj_bc_mode[];
 LJ_DATA const uint16_t lj_bc_ofs[];
 LJ_DATA const uint16_t lj_bc_ofs[];
 
 

+ 1 - 13
src/lj_parse.c

@@ -1529,23 +1529,11 @@ static void fs_fixup_var(LexState *ls, GCproto *pt, uint8_t *p, size_t ofsvar)
 
 
 #endif
 #endif
 
 
-/* Check if bytecode op returns. */
-static int bcopisret(BCOp op)
-{
-  switch (op) {
-  case BC_CALLMT: case BC_CALLT:
-  case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1:
-    return 1;
-  default:
-    return 0;
-  }
-}
-
 /* Fixup return instruction for prototype. */
 /* Fixup return instruction for prototype. */
 static void fs_fixup_ret(FuncState *fs)
 static void fs_fixup_ret(FuncState *fs)
 {
 {
   BCPos lastpc = fs->pc;
   BCPos lastpc = fs->pc;
-  if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) {
+  if (lastpc <= fs->lasttarget || !bc_isret_or_tail(bc_op(fs->bcbase[lastpc-1].ins))) {
     if ((fs->bl->flags & FSCOPE_UPVAL))
     if ((fs->bl->flags & FSCOPE_UPVAL))
       bcemit_AJ(fs, BC_UCLO, 0, 0);
       bcemit_AJ(fs, BC_UCLO, 0, 0);
     bcemit_AD(fs, BC_RET0, 0, 1);  /* Need final return. */
     bcemit_AD(fs, BC_RET0, 0, 1);  /* Need final return. */

+ 4 - 2
src/lj_snap.c

@@ -872,8 +872,10 @@ const BCIns *lj_snap_restore(jit_State *J, void *exptr)
   const BCIns *pc = snap_pc(map[nent]);
   const BCIns *pc = snap_pc(map[nent]);
   lua_State *L = J->L;
   lua_State *L = J->L;
 
 
-  /* Set interpreter PC to the next PC to get correct error messages. */
-  setcframe_pc(L->cframe, pc+1);
+  /* Set interpreter PC to the next PC to get correct error messages.
+  ** But not for returns or tail calls, since pc+1 may be out-of-range.
+  */
+  setcframe_pc(L->cframe, bc_isret_or_tail(bc_op(*pc)) ? pc : pc+1);
   setcframe_pc(cframe_raw(cframe_prev(L->cframe)), pc);
   setcframe_pc(cframe_raw(cframe_prev(L->cframe)), pc);
 
 
   /* Make sure the stack is big enough for the slots from the snapshot. */
   /* Make sure the stack is big enough for the slots from the snapshot. */