diff options
author | Mike Pall <mike> | 2025-05-28 21:02:31 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2025-05-28 21:02:31 +0200 |
commit | cd4af8ad80bb6430ad2e547f7af236268c9be7d9 (patch) | |
tree | 60cb40dd5a5d3cbec90b3563c9c750923d3542d8 /src | |
parent | 9c8eb7cfe10ef5939d9b358a0bd805a610818ba5 (diff) | |
download | luajit-cd4af8ad80bb6430ad2e547f7af236268c9be7d9.tar.gz luajit-cd4af8ad80bb6430ad2e547f7af236268c9be7d9.tar.bz2 luajit-cd4af8ad80bb6430ad2e547f7af236268c9be7d9.zip |
Avoid out-of-range PC for stack overflow error from snapshot restore.
Reported by Sergey Kaplun. #1359
Diffstat (limited to 'src')
-rw-r--r-- | src/lj_bc.h | 5 | ||||
-rw-r--r-- | src/lj_parse.c | 14 | ||||
-rw-r--r-- | src/lj_snap.c | 6 |
3 files changed, 10 insertions, 15 deletions
diff --git a/src/lj_bc.h b/src/lj_bc.h index 3f0563e4..0c7249b3 100644 --- a/src/lj_bc.h +++ b/src/lj_bc.h | |||
@@ -255,6 +255,11 @@ static LJ_AINLINE int bc_isret(BCOp op) | |||
255 | return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1); | 255 | return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1); |
256 | } | 256 | } |
257 | 257 | ||
258 | static LJ_AINLINE int bc_isret_or_tail(BCOp op) | ||
259 | { | ||
260 | return (op == BC_CALLMT || op == BC_CALLT || bc_isret(op)); | ||
261 | } | ||
262 | |||
258 | LJ_DATA const uint16_t lj_bc_mode[]; | 263 | LJ_DATA const uint16_t lj_bc_mode[]; |
259 | LJ_DATA const uint16_t lj_bc_ofs[]; | 264 | LJ_DATA const uint16_t lj_bc_ofs[]; |
260 | 265 | ||
diff --git a/src/lj_parse.c b/src/lj_parse.c index ffd11b3b..3370296f 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c | |||
@@ -1529,23 +1529,11 @@ static void fs_fixup_var(LexState *ls, GCproto *pt, uint8_t *p, size_t ofsvar) | |||
1529 | 1529 | ||
1530 | #endif | 1530 | #endif |
1531 | 1531 | ||
1532 | /* Check if bytecode op returns. */ | ||
1533 | static int bcopisret(BCOp op) | ||
1534 | { | ||
1535 | switch (op) { | ||
1536 | case BC_CALLMT: case BC_CALLT: | ||
1537 | case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1: | ||
1538 | return 1; | ||
1539 | default: | ||
1540 | return 0; | ||
1541 | } | ||
1542 | } | ||
1543 | |||
1544 | /* Fixup return instruction for prototype. */ | 1532 | /* Fixup return instruction for prototype. */ |
1545 | static void fs_fixup_ret(FuncState *fs) | 1533 | static void fs_fixup_ret(FuncState *fs) |
1546 | { | 1534 | { |
1547 | BCPos lastpc = fs->pc; | 1535 | BCPos lastpc = fs->pc; |
1548 | if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) { | 1536 | if (lastpc <= fs->lasttarget || !bc_isret_or_tail(bc_op(fs->bcbase[lastpc-1].ins))) { |
1549 | if ((fs->bl->flags & FSCOPE_UPVAL)) | 1537 | if ((fs->bl->flags & FSCOPE_UPVAL)) |
1550 | bcemit_AJ(fs, BC_UCLO, 0, 0); | 1538 | bcemit_AJ(fs, BC_UCLO, 0, 0); |
1551 | bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ | 1539 | bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ |
diff --git a/src/lj_snap.c b/src/lj_snap.c index 82ab6983..54260021 100644 --- a/src/lj_snap.c +++ b/src/lj_snap.c | |||
@@ -872,8 +872,10 @@ const BCIns *lj_snap_restore(jit_State *J, void *exptr) | |||
872 | const BCIns *pc = snap_pc(map[nent]); | 872 | const BCIns *pc = snap_pc(map[nent]); |
873 | lua_State *L = J->L; | 873 | lua_State *L = J->L; |
874 | 874 | ||
875 | /* Set interpreter PC to the next PC to get correct error messages. */ | 875 | /* Set interpreter PC to the next PC to get correct error messages. |
876 | setcframe_pc(L->cframe, pc+1); | 876 | ** But not for returns or tail calls, since pc+1 may be out-of-range. |
877 | */ | ||
878 | setcframe_pc(L->cframe, bc_isret_or_tail(bc_op(*pc)) ? pc : pc+1); | ||
877 | setcframe_pc(cframe_raw(cframe_prev(L->cframe)), pc); | 879 | setcframe_pc(cframe_raw(cframe_prev(L->cframe)), pc); |
878 | 880 | ||
879 | /* Make sure the stack is big enough for the slots from the snapshot. */ | 881 | /* Make sure the stack is big enough for the slots from the snapshot. */ |