Skip to content

Commit bd88a54

Browse files
committed
Ensure that type widening converges
Range analysis may fail to converge (the process hangs) when the transfer function zend_inference_calc_range produces a smaller range. Fix by ensuring that the widening operator zend_inference_widening_meet allows only widening. This matches the inference rules in figure 13 of the paper. Fixes phpGH-19679 Closes phpGH-19683
1 parent 080fd14 commit bd88a54

File tree

3 files changed

+27
-0
lines changed

3 files changed

+27
-0
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ PHP NEWS
1010
. Fixed bug GH-19544 (GC treats ZEND_WEAKREF_TAG_MAP references as WeakMap
1111
references). (Arnaud, timwolla)
1212
. Fixed bug GH-19613 (Stale array iterator pointer). (ilutov)
13+
. Fixed bug GH-19679 (zend_ssa_range_widening may fail to converge). (Arnaud)
1314

1415
- Date:
1516
. Fixed date_sunrise() and date_sunset() with partial-hour UTC offset.

Zend/Optimizer/zend_inference.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,12 +1633,16 @@ static bool zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_r
16331633
r->min < var_info->range.min) {
16341634
r->underflow = 1;
16351635
r->min = ZEND_LONG_MIN;
1636+
} else {
1637+
r->min = var_info->range.min;
16361638
}
16371639
if (r->overflow ||
16381640
var_info->range.overflow ||
16391641
r->max > var_info->range.max) {
16401642
r->overflow = 1;
16411643
r->max = ZEND_LONG_MAX;
1644+
} else {
1645+
r->max = var_info->range.max;
16421646
}
16431647
if (var_info->range.min == r->min &&
16441648
var_info->range.max == r->max &&

Zend/tests/gh19679.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-19679: zend_ssa_range_widening does not converge
3+
--SKIPIF--
4+
<?php
5+
if (PHP_INT_SIZE !== 8) {
6+
die('skip output depends PHP_INT_SIZE=8');
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
function test() {
12+
$a = PHP_INT_MIN+1;
13+
$b = 0;
14+
while ($b++ < 3) {
15+
$a = (int) ($a-- - $b - 1);
16+
}
17+
return $a;
18+
}
19+
var_dump(test() == PHP_INT_MIN);
20+
?>
21+
--EXPECT--
22+
bool(true)

0 commit comments

Comments
 (0)