Skip to content

Commit 3d38960

Browse files
committed
Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0: Fix range inference hang
2 parents e4f1083 + f8ec5a1 commit 3d38960

File tree

2 files changed

+30
-23
lines changed

2 files changed

+30
-23
lines changed

Zend/Optimizer/zend_inference.c

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -659,35 +659,26 @@ static int zend_inference_calc_binary_op_range(
659659
op2_min = OP2_MIN_RANGE();
660660
op1_max = OP1_MAX_RANGE();
661661
op2_max = OP2_MAX_RANGE();
662-
if (op2_min <= 0 && op2_max >= 0) {
663-
/* If op2 crosses zero, then floating point values close to zero might be
664-
* possible, which will result in arbitrarily large results. As such, we can't
665-
* do anything useful in that case. */
666-
break;
667-
}
668-
if (op1_min == ZEND_LONG_MIN && op2_max == -1) {
669-
/* Avoid ill-defined division, which may trigger SIGFPE. */
670-
break;
671-
}
672-
673-
zend_long t1_, t2_, t3_, t4_;
674-
float_div(op1_min, op2_min, &t1, &t1_);
675-
float_div(op1_min, op2_max, &t2, &t2_);
676-
float_div(op1_max, op2_min, &t3, &t3_);
677-
float_div(op1_max, op2_max, &t4, &t4_);
678662

679-
/* The only case in which division can "overflow" either a division by an absolute
680-
* value smaller than one, or LONG_MIN / -1 in particular. Both cases have already
681-
* been excluded above. */
682-
if (OP1_RANGE_UNDERFLOW() ||
683-
OP2_RANGE_UNDERFLOW() ||
684-
OP1_RANGE_OVERFLOW() ||
685-
OP2_RANGE_OVERFLOW()) {
663+
/* If op2 crosses zero, then floating point values close to zero might be
664+
* possible, which will result in arbitrarily large results (overflow). Also
665+
* avoid dividing LONG_MIN by -1, which is UB. */
666+
if (OP1_RANGE_UNDERFLOW() || OP2_RANGE_UNDERFLOW() ||
667+
OP1_RANGE_OVERFLOW() || OP2_RANGE_OVERFLOW() ||
668+
(op2_min <= 0 && op2_max >= 0) ||
669+
(op1_min == ZEND_LONG_MIN && op2_max == -1)
670+
) {
686671
tmp->underflow = 1;
687672
tmp->overflow = 1;
688673
tmp->min = ZEND_LONG_MIN;
689674
tmp->max = ZEND_LONG_MAX;
690675
} else {
676+
zend_long t1_, t2_, t3_, t4_;
677+
float_div(op1_min, op2_min, &t1, &t1_);
678+
float_div(op1_min, op2_max, &t2, &t2_);
679+
float_div(op1_max, op2_min, &t3, &t3_);
680+
float_div(op1_max, op2_max, &t4, &t4_);
681+
691682
tmp->min = MIN(MIN(MIN(t1, t2), MIN(t3, t4)), MIN(MIN(t1_, t2_), MIN(t3_, t4_)));
692683
tmp->max = MAX(MAX(MAX(t1, t2), MAX(t3, t4)), MAX(MAX(t1_, t2_), MAX(t3_, t4_)));
693684
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Range inference should not hang
3+
--FILE--
4+
<?php
5+
6+
function test() {
7+
$a = 0;
8+
while (true) {
9+
$a = $a+!$a=$a/!!~$a;
10+
}
11+
}
12+
13+
?>
14+
===DONE===
15+
--EXPECT--
16+
===DONE===

0 commit comments

Comments
 (0)