Skip to content

Commit e20adcc

Browse files
committed
Fixes
1 parent 2229f7b commit e20adcc

File tree

1 file changed

+27
-42
lines changed

1 file changed

+27
-42
lines changed

test/tarantool-tests/lj-736-BC_UCLO-triggers-infinite-loop.test.lua

+27-42
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,23 @@ local test = tap.test('lj-736-BC_UCLO-triggers-infinite-loop'):skipcond({
33
['Test requires JIT enabled'] = not jit.status(),
44
})
55

6-
test:plan(2)
7-
86
-- Test reproduces an issue when BC_UCLO triggers an infinite loop.
97
-- See details in https://github.com/LuaJIT/LuaJIT/issues/736.
10-
--
11-
-- Listing below demonstrates a problem -
12-
-- the bytecode UCLO on the line 13 makes a loop at 0013-0014:
13-
--
14-
-- - BYTECODE -- bc_uclo.lua:0-20
15-
-- 0001 KPRI 0 0
16-
-- 0002 FNEW 1 0 ; bc_uclo.lua:5
17-
-- 0003 KSHORT 2 1
18-
-- 0004 KSHORT 3 4
19-
-- 0005 KSHORT 4 1
20-
-- 0006 FORI 2 => 0011
21-
-- 0007 => ISNEN 5 0 ; 2
22-
-- 0008 JMP 6 => 0010
23-
-- 0009 UCLO 0 => 0012
24-
-- 0010 => FORL 2 => 0007
25-
-- 0011 => UCLO 0 => 0012
26-
-- 0012 => KPRI 0 0
27-
-- 0013 UCLO 0 => 0012
28-
-- 0014 FNEW 1 1 ; bc_uclo.lua:18
29-
-- 0015 UCLO 0 => 0016
30-
-- 0016 => RET0 0 1
8+
9+
test:plan(2)
10+
11+
-- Before the patch, the code flow like in the `testcase()` below
12+
-- may cause the problem -- use-def analysis for the 0019 UCLO
13+
-- creates an infinite loop in 0014 - 0019:
14+
-- | 0008 FORI base: 4 jump: => 0013
15+
-- | 0009 ISNEN var: 7 num: 0 ; number 2
16+
-- | 0010 JMP rbase: 8 jump: => 0012
17+
-- | 0011 UCLO rbase: 2 jump: => 0014
18+
-- | 0012 FORL base: 4 jump: => 0009
19+
-- | 0013 UCLO rbase: 2 jump: => 0014
20+
-- | 0014 KPRI dst: 2 pri: 0 ; Start of `assert()` line.
21+
-- | ...
22+
-- | 0019 UCLO rbase: 2 jump: => 0014
3123

3224
jit.opt.start('hotloop=1')
3325

@@ -36,20 +28,17 @@ local assert = assert
3628

3729
local function testcase()
3830
-- The code in the first scope `do`/`end` is a prerequisite.
39-
-- It is needed so that we have a trace at the exit from which
40-
-- the creation of the snapshot will begin.
31+
-- It contains the UCLO instruction for the `uv1`. The use-def
32+
-- analysis for it escapes this `do`/`end` scope.
4133
do
42-
-- Upvalue below is not used actually, but it is required
43-
-- for calling `snap_usedef()` on trace exit.
44-
local uv1 -- luacheck: ignore
34+
local uv1 -- luacheck: no unused
4535
local _ = function() return uv1 end
4636

47-
-- The loop below is required for recording a trace.
48-
-- The condition inside a loop executes `goto` to a label
49-
-- outside of the loop when the code executed by JIT and
50-
-- this triggers snapshotting.
37+
-- Records the trace for which use-def analysis is applied.
5138
for i = 1, 2 do
52-
-- Exit to interpreter once trace is compiled.
39+
-- This condition triggers snapshoting and use-def analysis.
40+
-- Before the patch this triggers the infinite loop in the
41+
-- `snap_usedef()`, so the `goto` is never taken.
5342
if i == 2 then
5443
goto x
5544
end
@@ -60,16 +49,12 @@ local function testcase()
6049
do
6150
local uv2 -- luacheck: no unused
6251

63-
-- `goto` if not executed without a patch and generates an
64-
-- UCLO bytecode that makes an infinite loop in a function
65-
-- `snap_usedef` when patch is not applied. `goto` must point
66-
-- to the label on one of the previous lines. `assert()` is
67-
-- executed when patch is applied.
52+
-- Create a tight loop for the one more upvalue (`uv2`).
53+
-- Before the patch, use-def analysis gets stuck in this code
54+
-- flow.
6855
assert(nil, assert_msg)
6956
goto x
70-
71-
-- Line below is required, it makes `uv` upvalue, and must be
72-
-- placed after `goto`, otherwise reproducer become broken.
57+
-- This code is unreachable by design.
7358
local _ = function() return uv2 end -- luacheck: ignore
7459
end
7560
end
@@ -79,4 +64,4 @@ local ok, err = pcall(testcase)
7964
test:is(ok, false, 'assertion is triggered in a function with testcase')
8065
test:ok(err:match(assert_msg), 'BC_UCLO does not trigger an infinite loop')
8166

82-
os.exit(test:check() and 0 or 1)
67+
test:done(true)

0 commit comments

Comments
 (0)