Skip to content

Commit

Permalink
Fix string.char() recording with no arguments.
Browse files Browse the repository at this point in the history
(cherry picked from commit dfa692b)

`string.char()` call without arguments yields an empty string. When JIT
machinery records the aforementioned call it doesn't handle case without
arguments. Each recording fast function expects 1 result by default.
Hence, when return from this call is recorded the framelink slot is used
as a result. It is loaded into the corresponding slot as an IR with
`IRT_NUM` type. It leads to assertion failure in `rec_check_slots()`,
when a next bytecode is recorded, because type of TV on the stack
(`LJ_STR`) isn't the same as IR (and TRef) type.

This patch handles the case without arguments by the loading of IR with
empty string reference into the corresponding slot.

Sergey Kaplun:
* added the description and the test for the problem

Resolves tarantool/tarantool#6371
  • Loading branch information
Mike Pall authored and Buristan committed Aug 20, 2021
1 parent 814625f commit 832847d
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/lj_ffrecord.c
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,8 @@ static void LJ_FASTCALL recff_string_char(jit_State *J, RecordFFData *rd)
for (i = 0; J->base[i] != 0; i++)
tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, J->base[i]);
J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
} else if (i == 0) {
J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty);
}
UNUSED(rd);
}
Expand Down
28 changes: 28 additions & 0 deletions test/tarantool-tests/gh-6371-string-char-no-arg.test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
local tap = require('tap')

-- Test file to demonstrate assertion after `string.char()`
-- recording.
-- See also, https://github.com/tarantool/tarantool/issues/6371.

local test = tap.test('gh-6371-string-char-no-arg')
-- XXX: Number of loop iterations.
-- 1, 2 -- instruction becomes hot
-- 3 -- trace is recorded (considering loop recording specifics),
-- but bytecodes are still executed via VM
-- 4 -- trace is executed, need to check that emitted mcode is
-- correct
local NTEST = 4
test:plan(NTEST)

-- Storage for the results to avoid trace aborting by `test:ok()`.
local results = {}
jit.opt.start('hotloop=1')
for _ = 1, NTEST do
table.insert(results, string.char())
end

for i = 1, NTEST do
test:ok(results[i] == '', 'correct recording of string.char() without args')
end

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

0 comments on commit 832847d

Please sign in to comment.