Skip to content

Commit

Permalink
Mark CONV as non-weak, to prevent elimination of its side-effect.
Browse files Browse the repository at this point in the history
An unused guarded CONV int.num cannot be omitted in general.

(cherry-picked from commit 881d02d)

In some cases, an unused `CONV int.num` omission in `DUALNUM` mode
may lead to a guard absence, resulting in invalid control flow
branching and undefined behavior. For a comprehensive example of
the described situation, please refer to the comment
in `test/tarantool-tests/mark-conv-non-weak.test.lua`.

Maxim Kokryashkin:
* added the description and the test for the problem

Part of tarantool/tarantool#8825
  • Loading branch information
Mike Pall authored and mkokryashkin committed Jul 17, 2023
1 parent 8e46d60 commit 68cc359
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/lj_ir.h
Expand Up @@ -132,7 +132,7 @@
_(XBAR, S , ___, ___) \
\
/* Type conversions. */ \
_(CONV, NW, ref, lit) \
_(CONV, N , ref, lit) \
_(TOBIT, N , ref, ref) \
_(TOSTR, N , ref, lit) \
_(STRTO, N , ref, ___) \
Expand Down
62 changes: 62 additions & 0 deletions test/tarantool-tests/mark-conv-non-weak.test.lua
@@ -0,0 +1,62 @@
local tap = require('tap')
local test = tap.test('mark-conv-non-weak'):skipcond({
['Test requires JIT enabled'] = not jit.status(),
})

test:plan(1)

local data = {0.1, 0, 0.1, 0, 0 / 0}
local sum = 0

jit.opt.start('hotloop=1', 'hotexit=1')

-- XXX: The test fails before the patch only
-- for `DUALNUM` mode. All of the IRs below are
-- produced by the corresponding LuaJIT build.

-- When the last trace is recorded, the traced bytecode
-- is the following before the patch:
-- ---- TRACE 4 start 2/3 test.lua:6
-- 0018 ADDVV 1 1 6
-- 0019 ITERC 5 3 3
-- 0000 . FUNCC ; ipairs_aux
-- 0020 JITERL 5 1
-- 0021 GGET 2 7 ; "assert"
-- 0022 ISEQV 1 1
-- 0023 JMP 4 => 0026
-- 0024 KPRI 4 1
-- 0025 JMP 5 => 0027
-- 0027 CALL 2 1 2
-- 0000 . FUNCC ; assert
--
-- And the following after the patch:
-- ---- TRACE 4 start 2/2 test.lua:5
-- 0016 ISNEV 6 6
-- 0017 JMP 7 => 0019
-- 0019 ITERC 5 3 3
-- 0000 . FUNCC ; ipairs_aux
-- 0020 JITERL 5 1
-- 0021 GGET 2 7 ; "assert"
-- 0022 ISEQV 1 1
-- 0023 JMP 4 => 0026
-- 0026 KPRI 4 2
-- 0027 CALL 2 1 2
-- 0000 . FUNCC ; assert
-- 0028 RET0 0 1
--
-- The crucial difference here is the abscent
-- `ISNEV` in the first case, which produces the
-- desired guarded `CONV`, when translated to IR.
--
-- Since there is no guard, NaN is added to the sum,
-- despite the test case logic.

for _, val in ipairs(data) do
if val == val then
sum = sum + val
end
end

test:ok(sum == sum, 'NaN check was not omitted')

os.exit(test:check() and 0 or 1)

0 comments on commit 68cc359

Please sign in to comment.