Incorrect narrowing for huge numbers.

Ouverte
#1,236 1 commentaire 1 réaction 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
18/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
À l'abandon
Stack technique
c
Domaine
compilers

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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 
Langage dominant
C
Étoiles
5.8k
Forks
1.2k
Métriques de merge des PR
Aucune PR mergée en 30 j

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de LuaJIT/LuaJIT

Toutes les issues de LuaJIT/LuaJIT

Issues similaires

Plus d'issues C

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.