diff --git a/src/lj_record.c b/src/lj_record.c index 7181b72ab4..5345fa6343 100644 --- a/src/lj_record.c +++ b/src/lj_record.c @@ -1869,7 +1869,7 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults) J->maxslot = dst + (BCReg)nresults; } } else if (select_detect(J)) { /* y = select(x, ...) */ - TRef tridx = J->base[dst-1]; + TRef tridx = getslot(J, dst-1); TRef tr = TREF_NIL; ptrdiff_t idx = lj_ffrecord_select_mode(J, tridx, &J->L->base[dst-1]); if (idx < 0) goto nyivarg; diff --git a/test/tarantool-tests/fix-recording-bc-varg-used-in-select.test.lua b/test/tarantool-tests/fix-recording-bc-varg-used-in-select.test.lua new file mode 100644 index 0000000000..b3a62b5ce9 --- /dev/null +++ b/test/tarantool-tests/fix-recording-bc-varg-used-in-select.test.lua @@ -0,0 +1,36 @@ +local tap = require('tap') + +-- Test file to demonstrate incorrect recording of `BC_VARG` that +-- is given to the `select()` function. See also: +-- https://www.freelists.org/post/luajit/Possible-issue-during-register-allocation-ra-alloc1. + +local test = tap.test('fix-recording-bc-varg-used-in-select'):skipcond({ + ['Test requires JIT enabled'] = not jit.status(), +}) + +test:plan(1) + +-- XXX: Simplify `jit.dump` output. +local modf = math.modf + +local EXPECTED = 'canary' +local function test_func(...) + local first_varg_item + for _ = 1, 4 do + -- `modf()` is used to create a stitching with a meaningful + -- index value, that equals 1, i.e. refers to the first item + -- in `...`. The second trace started after stitching does not + -- contain the stack slot for the first argument of the + -- `select()`. Before the patch, there is no loading of + -- this slot for the trace and the 0 value is taken instead. + -- Hence, this leads to an incorrect recording of the + -- `BC_VARG` with detected `select()`. + first_varg_item = select(modf(1, 0), ...) + end + return first_varg_item +end + +jit.opt.start('hotloop=1') +test:is(test_func(EXPECTED), EXPECTED, 'correct BC_VARG recording') + +test:done(true)