Skip to content

Commit 4986aab

Browse files
Mike PallBuristan
Mike Pall
authored andcommitted
FFI: Add missing coercion when recording 64-bit bit.*().
Thanks to Peter Cawley. (cherry picked from commit 304da39) Before the patch, with the missed coercion from string, there is the cast to `i64` from `p64`, where the last one is the string address. This leads to an incorrect result of the bit operation. This patch adds the missing coercion everywhere for bit operations recording. Only the `recff_bit64_nary()` is affected, since all other routines have the corresponding type check and cast emitting if necessary. However, for the consistency, all functions have the same checking routine `crec_bit64_arg()` now. Sergey Kaplun: * added the description and the test for the problem Part of tarantool/tarantool#10709 Reviewed-by: Sergey Bronnikov <[email protected]> Signed-off-by: Sergey Kaplun <[email protected]> (cherry picked from commit c698ff5)
1 parent 86389f8 commit 4986aab

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

src/Makefile.dep.original

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
9696
lj_cdata.h lj_cparse.h lj_cconv.h lj_carith.h lj_clib.h lj_ccall.h \
9797
lj_ff.h lj_ffdef.h lj_ir.h lj_jit.h lj_ircall.h lj_iropt.h lj_trace.h \
9898
lj_dispatch.h lj_traceerr.h lj_record.h lj_ffrecord.h lj_snap.h \
99-
lj_crecord.h lj_strfmt.h
99+
lj_crecord.h lj_strfmt.h lj_strscan.h
100100
lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
101101
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_strfmt.h lj_ctype.h \
102102
lj_ccallback.h lj_buf.h

src/lj_crecord.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "lj_crecord.h"
3333
#include "lj_dispatch.h"
3434
#include "lj_strfmt.h"
35+
#include "lj_strscan.h"
3536

3637
/* Some local macros to save typing. Undef'd at the end. */
3738
#define IR(ref) (&J->cur.ir[(ref)])
@@ -1782,11 +1783,21 @@ static CTypeID crec_bit64_type(CTState *cts, cTValue *tv)
17821783
return 0; /* Use regular 32 bit ops. */
17831784
}
17841785

1786+
static TRef crec_bit64_arg(jit_State *J, CType *d, TRef sp, TValue *sval)
1787+
{
1788+
if (LJ_UNLIKELY(tref_isstr(sp))) {
1789+
if (lj_strscan_num(strV(sval), sval)) {
1790+
sp = emitir(IRTG(IR_STRTO, IRT_NUM), sp, 0);
1791+
} /* else: interpreter will throw. */
1792+
}
1793+
return crec_ct_tv(J, d, 0, sp, sval);
1794+
}
1795+
17851796
void LJ_FASTCALL recff_bit64_tobit(jit_State *J, RecordFFData *rd)
17861797
{
17871798
CTState *cts = ctype_ctsG(J2G(J));
1788-
TRef tr = crec_ct_tv(J, ctype_get(cts, CTID_INT64), 0,
1789-
J->base[0], &rd->argv[0]);
1799+
TRef tr = crec_bit64_arg(J, ctype_get(cts, CTID_INT64),
1800+
J->base[0], &rd->argv[0]);
17901801
if (!tref_isinteger(tr))
17911802
tr = emitconv(tr, IRT_INT, tref_type(tr), 0);
17921803
J->base[0] = tr;
@@ -1797,7 +1808,7 @@ int LJ_FASTCALL recff_bit64_unary(jit_State *J, RecordFFData *rd)
17971808
CTState *cts = ctype_ctsG(J2G(J));
17981809
CTypeID id = crec_bit64_type(cts, &rd->argv[0]);
17991810
if (id) {
1800-
TRef tr = crec_ct_tv(J, ctype_get(cts, id), 0, J->base[0], &rd->argv[0]);
1811+
TRef tr = crec_bit64_arg(J, ctype_get(cts, id), J->base[0], &rd->argv[0]);
18011812
tr = emitir(IRT(rd->data, id-CTID_INT64+IRT_I64), tr, 0);
18021813
J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr);
18031814
return 1;
@@ -1817,9 +1828,9 @@ int LJ_FASTCALL recff_bit64_nary(jit_State *J, RecordFFData *rd)
18171828
if (id) {
18181829
CType *ct = ctype_get(cts, id);
18191830
uint32_t ot = IRT(rd->data, id-CTID_INT64+IRT_I64);
1820-
TRef tr = crec_ct_tv(J, ct, 0, J->base[0], &rd->argv[0]);
1831+
TRef tr = crec_bit64_arg(J, ct, J->base[0], &rd->argv[0]);
18211832
for (i = 1; J->base[i] != 0; i++) {
1822-
TRef tr2 = crec_ct_tv(J, ct, 0, J->base[i], &rd->argv[i]);
1833+
TRef tr2 = crec_bit64_arg(J, ct, J->base[i], &rd->argv[i]);
18231834
tr = emitir(ot, tr, tr2);
18241835
}
18251836
J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr);
@@ -1834,15 +1845,15 @@ int LJ_FASTCALL recff_bit64_shift(jit_State *J, RecordFFData *rd)
18341845
CTypeID id;
18351846
TRef tsh = 0;
18361847
if (J->base[0] && tref_iscdata(J->base[1])) {
1837-
tsh = crec_ct_tv(J, ctype_get(cts, CTID_INT64), 0,
1838-
J->base[1], &rd->argv[1]);
1848+
tsh = crec_bit64_arg(J, ctype_get(cts, CTID_INT64),
1849+
J->base[1], &rd->argv[1]);
18391850
if (!tref_isinteger(tsh))
18401851
tsh = emitconv(tsh, IRT_INT, tref_type(tsh), 0);
18411852
J->base[1] = tsh;
18421853
}
18431854
id = crec_bit64_type(cts, &rd->argv[0]);
18441855
if (id) {
1845-
TRef tr = crec_ct_tv(J, ctype_get(cts, id), 0, J->base[0], &rd->argv[0]);
1856+
TRef tr = crec_bit64_arg(J, ctype_get(cts, id), J->base[0], &rd->argv[0]);
18461857
uint32_t op = rd->data;
18471858
if (!tsh) tsh = lj_opt_narrow_tobit(J, J->base[1]);
18481859
if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) &&
@@ -1872,7 +1883,7 @@ TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr)
18721883
CTypeID id2 = 0;
18731884
n = (int32_t)lj_carith_check64(J->L, 2, &id2);
18741885
if (id2)
1875-
trsf = crec_ct_tv(J, ctype_get(cts, CTID_INT32), 0, trsf, &rd->argv[1]);
1886+
trsf = crec_bit64_arg(J, ctype_get(cts, CTID_INT32), trsf, &rd->argv[1]);
18761887
else
18771888
trsf = lj_opt_narrow_tobit(J, trsf);
18781889
emitir(IRTGI(IR_EQ), trsf, lj_ir_kint(J, n)); /* Specialize to n. */
@@ -1883,7 +1894,7 @@ TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr)
18831894
if ((uint32_t)n > 254) n = 254;
18841895
sf |= ((SFormat)((n+1)&255) << STRFMT_SH_PREC);
18851896
if (id) {
1886-
tr = crec_ct_tv(J, ctype_get(cts, id), 0, J->base[0], &rd->argv[0]);
1897+
tr = crec_bit64_arg(J, ctype_get(cts, id), J->base[0], &rd->argv[0]);
18871898
if (n < 16)
18881899
tr = emitir(IRT(IR_BAND, IRT_U64), tr,
18891900
lj_ir_kint64(J, ((uint64_t)1 << 4*n)-1));
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
local tap = require('tap')
2+
3+
-- Test file to demonstrate LuaJIT incorrect recording of
4+
-- `bit` library with needed coercion from string.
5+
-- See also: https://github.com/LuaJIT/LuaJIT/issues/1252.
6+
7+
local test = tap.test('lj-1252-missing-bit64-coercion'):skipcond({
8+
['Test requires JIT enabled'] = not jit.status(),
9+
})
10+
11+
test:plan(1)
12+
13+
-- Simplify the `jit.dump()` output.
14+
local bor = bit.bor
15+
16+
jit.opt.start('hotloop=1')
17+
18+
-- Before the patch, with the missed coercion from string, there
19+
-- is the cast to `i64` from `p64`, where the last one is the
20+
-- string address. This leads to an incorrect result of the bit
21+
-- operation.
22+
23+
local results = {}
24+
for i = 1, 4 do
25+
results[i] = bor('0', 0LL)
26+
end
27+
28+
test:samevalues(results, 'correct recording of the bit operation with coercion')
29+
30+
test:done(true)

0 commit comments

Comments
 (0)