Incorrect narrowing for huge numbers.
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 18/100
Direção de pesquisa
The bug is in the narrowing pass of the JIT, so start in src/lj_opt_narrow.c, at narrow_conv_emit, where the integer conversion is emitted. Reproduce with src/luajit -Ohotloop=1 using the s + 1 - 0LL - s loop from the issue, and compare against jit.off(). Done when the traced results match the interpreter for values at or beyond 2^53, and the trace dump shows the range guard.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Mantissa precision of IEEE-754 doubles can't store integral types precision for |x| >= 2^53.
That means that premature folding optimization may lead to invalid results in cases like the following:
x + 1 + 0LL - x => 1LL; x >= 2^53
x - 1 + 0LL - x => -1LL; x <= -2^53
since it changes the semantics of operations to (int)x + 1LL instead of (int)((double)x + 1.) + 0LL.
Lua examples of this misbehaviour:
src/luajit -Ohotloop=1 -e '
local s = 2^53
local v = {}
for i = 1, 4 do
v[i] = s + 1 - 0LL - s
end
jit.off()
for i = 1, 4 do
print(i,v[i])
end
'
1 0LL
2 0LL
3 0LL
4 1LL
or vice versa for substracture:
src/luajit -Ohotloop=1 -e '
local s = -2^53
local v = {}
for i = 1, 4 do
v[i] = s - 1 - 0LL - s
end
jit.off()
for i = 1, 4 do
print(i,v[i])
end
'
1 0LL
2 0LL
3 0LL
4 -1LL
The start of the trace looks like the following with enabled narrowing:
---- TRACE 1 start (command line):4
---- TRACE 1 IR
0001 int SLOAD #4 CI
0002 > num SLOAD #2 T
0007 > cdt CNEWI +11 +1
And like the following with disabled:
0001 num SLOAD #4 I
0002 > num SLOAD #2 T
0003 num ADD 0002 +1
0004 i64 CONV 0003 i64.num none
0006 i64 CONV 0002 i64.num none
0007 i64 SUB 0004 0006
0008 > cdt CNEWI +11 0007
One of the ways to fix it is to add an assertion guard before corresponding conversions (it seems harmless for the SPEC benchmarks).
PoC workaround for the problem:
diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c
index db0da10f..5dd3819c 100644
--- a/src/lj_opt_narrow.c
+++ b/src/lj_opt_narrow.c
@@ -370,6 +370,15 @@ static IRRef narrow_conv_emit(jit_State *J, NarrowConv *nc)
if (op == NARROW_REF) {
*sp++ = ref;
} else if (op == NARROW_CONV) {
+ if (fins->o == IR_CONV && (fins->op2 & IRCONV_SRCMASK) == IRT_NUM) {
+ IRIns *srcins = IR(fins->op1);
+ if (srcins->o == IR_SUB)
+ emitir(IRTG(IR_GT, IRT_NUM), srcins->op1,
+ lj_ir_knum(J, -(lua_Number)(1LL<<52)));
+ else if (srcins->o == IR_ADD)
+ emitir(IRTG(IR_LT, IRT_NUM), srcins->op1,
+ lj_ir_knum(J, (lua_Number)(1LL<<52)));
+ }
*sp++ = emitir_raw(convot, ref, convop2); /* Raw emit avoids a loop. */
} else if (op == NARROW_SEXT) {
lj_assertJ(sp >= nc->stack+1, "stack underflow");
The start of a trace after the patch looks like the following:
---- TRACE 1 IR
0001 int SLOAD #4 CI
0002 > num SLOAD #2 T
0004 > num LT 0002 +4.5035996273705e+15
0008 > cdt CNEWI +11 +1
- Linguagem predominante
- C
- Estrelas
- 5.8k
- Forks
- 1.2k
- Métricas de merge de PRs
- Nenhum PR com merge em 30d
Preparar o ambiente
Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de LuaJIT/LuaJIT
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 74/100
-
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 35/100
-
3.0 enhancement
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 12/100
-
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 18/100
-
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 30/100
Todas as issues de LuaJIT/LuaJIT
Issues semelhantes
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
micropython/micropython#19906 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 75/100
Mantenedores costumam responder em até 10 dias
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 1/5 1-3 horas Facilidade para iniciantes 83/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
sk3llo/ffmpeg_kit_flutter#176 ·