@@ -548,6 +548,19 @@ static inline zend_bool shift_left_overflows(zend_long n, zend_long s) {
548
548
}
549
549
}
550
550
551
+ /* If b does not divide a exactly, return the two adjacent values between which the real result
552
+ * lies. */
553
+ static void float_div (zend_long a , zend_long b , zend_long * r1 , zend_long * r2 ) {
554
+ * r1 = * r2 = a / b ;
555
+ if (a % b != 0 ) {
556
+ if (* r2 < 0 ) {
557
+ (* r2 )-- ;
558
+ } else {
559
+ (* r2 )++ ;
560
+ }
561
+ }
562
+ }
563
+
551
564
static int zend_inference_calc_binary_op_range (
552
565
const zend_op_array * op_array , zend_ssa * ssa ,
553
566
zend_op * opline , zend_ssa_op * ssa_op , zend_uchar opcode , zend_ssa_range * tmp ) {
@@ -644,32 +657,36 @@ static int zend_inference_calc_binary_op_range(
644
657
op1_max = OP1_MAX_RANGE ();
645
658
op2_max = OP2_MAX_RANGE ();
646
659
if (op2_min <= 0 && op2_max >= 0 ) {
660
+ /* If op2 crosses zero, then floating point values close to zero might be
661
+ * possible, which will result in arbitrarily large results. As such, we can't
662
+ * do anything useful in that case. */
647
663
break ;
648
664
}
649
665
if (op1_min == ZEND_LONG_MIN && op2_max == -1 ) {
650
666
/* Avoid ill-defined division, which may trigger SIGFPE. */
651
667
break ;
652
668
}
653
- t1 = op1_min / op2_min ;
654
- t2 = op1_min / op2_max ;
655
- t3 = op1_max / op2_min ;
656
- t4 = op1_max / op2_max ;
657
- // FIXME: more careful overflow checks?
669
+
670
+ zend_long t1_ , t2_ , t3_ , t4_ ;
671
+ float_div (op1_min , op2_min , & t1 , & t1_ );
672
+ float_div (op1_min , op2_max , & t2 , & t2_ );
673
+ float_div (op1_max , op2_min , & t3 , & t3_ );
674
+ float_div (op1_max , op2_max , & t4 , & t4_ );
675
+
676
+ /* The only case in which division can "overflow" either a division by an absolute
677
+ * value smaller than one, or LONG_MIN / -1 in particular. Both cases have already
678
+ * been excluded above. */
658
679
if (OP1_RANGE_UNDERFLOW () ||
659
680
OP2_RANGE_UNDERFLOW () ||
660
681
OP1_RANGE_OVERFLOW () ||
661
- OP2_RANGE_OVERFLOW () ||
662
- t1 != (zend_long )((double )op1_min / (double )op2_min ) ||
663
- t2 != (zend_long )((double )op1_min / (double )op2_max ) ||
664
- t3 != (zend_long )((double )op1_max / (double )op2_min ) ||
665
- t4 != (zend_long )((double )op1_max / (double )op2_max )) {
682
+ OP2_RANGE_OVERFLOW ()) {
666
683
tmp -> underflow = 1 ;
667
684
tmp -> overflow = 1 ;
668
685
tmp -> min = ZEND_LONG_MIN ;
669
686
tmp -> max = ZEND_LONG_MAX ;
670
687
} else {
671
- tmp -> min = MIN (MIN (t1 , t2 ), MIN (t3 , t4 ));
672
- tmp -> max = MAX (MAX (t1 , t2 ), MAX (t3 , t4 ));
688
+ tmp -> min = MIN (MIN (MIN ( t1 , t2 ), MIN (t3 , t4 )), MIN ( MIN ( t1_ , t2_ ), MIN ( t3_ , t4_ ) ));
689
+ tmp -> max = MAX (MAX (MAX ( t1 , t2 ), MAX (t3 , t4 )), MAX ( MAX ( t1_ , t2_ ), MAX ( t3_ , t4_ ) ));
673
690
}
674
691
return 1 ;
675
692
}
0 commit comments