Skip to content

Commit 2cb93dd

Browse files
Mike Palligormunkin
Mike Pall
authored andcommitted
Fix snapshot PC when linking to BC_JLOOP that was a BC_RET*.
Reported by Arseny Vakhrushev. Fix contributed by Peter Cawley. (cherry-picked from commit 5c46f47) As specified in the comment in `lj_record_stop`, all loops must set `J->pc` to the next instruction. However, the chunk of logic in `lj_trace_exit` expects it to be set to `BC_JLOOP` itself if it used to be a `BC_RET`. This wrong pc results in the execution of random data that goes after `BC_JLOOP` in the case of restoration from the snapshot. This patch fixes that behavior by adapting the loop recording logic to this specific case. NOTICE: This patch is only a part of the original commit, and the other part is backported in the previous commit. The patch was split into two, so the test case becomes easier to implement since it can now depend on this assertion instead of memory layout. Maxim Kokryashkin: * added the description and the test for the problem Part of tarantool/tarantool#9145 Reviewed-by: Sergey Kaplun <[email protected]> Reviewed-by: Sergey Bronnikov <[email protected]> Signed-off-by: Igor Munkin <[email protected]> (cherry picked from commit 2ab0419)
1 parent 747f0b5 commit 2cb93dd

File tree

2 files changed

+88
-4
lines changed

2 files changed

+88
-4
lines changed

src/lj_record.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -570,10 +570,10 @@ static LoopEvent rec_iterl(jit_State *J, const BCIns iterins)
570570
}
571571

572572
/* Record LOOP/JLOOP. Now, that was easy. */
573-
static LoopEvent rec_loop(jit_State *J, BCReg ra)
573+
static LoopEvent rec_loop(jit_State *J, BCReg ra, int skip)
574574
{
575575
if (ra < J->maxslot) J->maxslot = ra;
576-
J->pc++;
576+
J->pc += skip;
577577
return LOOPEV_ENTER;
578578
}
579579

@@ -2441,7 +2441,7 @@ void lj_record_ins(jit_State *J)
24412441
rec_loop_interp(J, pc, rec_iterl(J, *pc));
24422442
break;
24432443
case BC_LOOP:
2444-
rec_loop_interp(J, pc, rec_loop(J, ra));
2444+
rec_loop_interp(J, pc, rec_loop(J, ra, 1));
24452445
break;
24462446

24472447
case BC_JFORL:
@@ -2451,7 +2451,8 @@ void lj_record_ins(jit_State *J)
24512451
rec_loop_jit(J, rc, rec_iterl(J, traceref(J, rc)->startins));
24522452
break;
24532453
case BC_JLOOP:
2454-
rec_loop_jit(J, rc, rec_loop(J, ra));
2454+
rec_loop_jit(J, rc, rec_loop(J, ra,
2455+
!bc_isret(bc_op(traceref(J, rc)->startins))));
24552456
break;
24562457

24572458
case BC_IFORL:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
local tap = require('tap')
2+
local test = tap.test('lj-624-jloop-snapshot-pc'):skipcond({
3+
['Test requires JIT enabled'] = not jit.status(),
4+
})
5+
6+
test:plan(1)
7+
-- XXX: The test case below triggers the assertion that was
8+
-- added in the patch if tested without the fix itself. It
9+
-- is hard to create a stable reproducer without turning off
10+
-- ASLR and VM randomizations, which is not suitable for testing.
11+
12+
-- Reproducer below produces the following traces:
13+
-- ---- TRACE 1 start test.lua:2
14+
-- 0001 KSHORT 1 2
15+
-- 0002 ISGE 0 1
16+
-- 0003 JMP 1 => 0006
17+
-- 0006 UGET 1 0 ; fib
18+
-- 0007 SUBVN 2 0 0 ; 1
19+
-- 0008 CALL 1 2 2
20+
-- 0000 . FUNCF 4 ; test.lua:2
21+
-- 0001 . KSHORT 1 2
22+
-- 0002 . ISGE 0 1
23+
-- 0003 . JMP 1 => 0006
24+
-- 0006 . UGET 1 0 ; fib
25+
-- 0007 . SUBVN 2 0 0 ; 1
26+
-- 0008 . CALL 1 2 2
27+
-- 0000 . . FUNCF 4 ; test.lua:2
28+
-- 0001 . . KSHORT 1 2
29+
-- 0002 . . ISGE 0 1
30+
-- 0003 . . JMP 1 => 0006
31+
-- 0006 . . UGET 1 0 ; fib
32+
-- 0007 . . SUBVN 2 0 0 ; 1
33+
-- 0008 . . CALL 1 2 2
34+
-- 0000 . . . FUNCF 4 ; test.lua:2
35+
-- ---- TRACE 1 stop -> up-recursion
36+
--
37+
-- ---- TRACE 1 exit 1
38+
-- ---- TRACE 2 start 1/1 test.lua:3
39+
-- 0004 ISTC 1 0
40+
-- 0005 JMP 1 => 0013
41+
-- 0013 RET1 1 2
42+
-- 0009 UGET 2 0 ; fib
43+
-- 0010 SUBVN 3 0 1 ; 2
44+
-- 0011 CALL 2 2 2
45+
-- 0000 . JFUNCF 4 1 ; test.lua:2
46+
-- ---- TRACE 2 stop -> 1
47+
--
48+
-- ---- TRACE 2 exit 1
49+
-- ---- TRACE 3 start 2/1 test.lua:3
50+
-- 0013 RET1 1 2
51+
-- 0012 ADDVV 1 1 2
52+
-- 0013 RET1 1 2
53+
-- ---- TRACE 3 abort test.lua:3 -- down-recursion, restarting
54+
--
55+
-- ---- TRACE 3 start test.lua:3
56+
-- 0013 RET1 1 2
57+
-- 0009 UGET 2 0 ; fib
58+
-- 0010 SUBVN 3 0 1 ; 2
59+
-- 0011 CALL 2 2 2
60+
-- 0000 . JFUNCF 4 1 ; test.lua:2
61+
-- ---- TRACE 3 stop -> 1
62+
--
63+
-- ---- TRACE 2 exit 1
64+
-- ---- TRACE 4 start 2/1 test.lua:3
65+
-- 0013 RET1 1 2
66+
-- 0012 ADDVV 1 1 2
67+
-- 0013 JLOOP 3 3
68+
--
69+
-- The assertion introduced in the previous patch is triggered during
70+
-- recording of the last 0013 JLOOP.
71+
--
72+
-- See also:
73+
-- https://github.com/luaJIT/LuaJIT/issues/624
74+
75+
jit.opt.start('hotloop=1', 'hotexit=1')
76+
local function fib(n)
77+
return n < 2 and n or fib(n - 1) + fib(n - 2)
78+
end
79+
80+
fib(5)
81+
82+
test:ok(true, 'snapshot pc is correct')
83+
test:done(true)

0 commit comments

Comments
 (0)