Skip to content

Commit 5162097

Browse files
committed
ext/opcache: Fix tracing JIT range narrowing against a non-integer operand
zend_jit_trace_update_condition_ranges() tested OP1_INFO() twice instead of OP1_INFO() and OP2_INFO(), so comparing an integer with a float or numeric-string literal narrowed the integer's range as if both operands were integers. zend_may_overflow() then ruled out overflow of a following $x + 1, the overflow check was omitted, and the trace returned a wrapped integer instead of a float, or failed an assertion while compiling. Require both operands to be integers, as the rest of the function assumes.
1 parent cfe77b8 commit 5162097

3 files changed

Lines changed: 61 additions & 1 deletion

File tree

‎NEWS‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ PHP NEWS
8585
zend_jit_assign_dim_op()). (waroad)
8686
. Fixed bug GH-24398 (JIT: minimal JIT segfault when a hooked property is
8787
passed to a run-time-resolved function). (waroad)
88+
. Fixed tracing JIT returning a wrapped integer instead of a float on
89+
integer overflow after an integer was compared with a float or
90+
numeric-string literal. (Ilia Alshanetsky)
8891

8992
- PDO:
9093
. Fixed invalid ATTR_ORACLE_NULLS values being accepted and truncated.

‎ext/opcache/jit/zend_jit_trace.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3688,7 +3688,7 @@ static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const
36883688
zend_long op1_min, op1_max, op2_min, op2_max;
36893689

36903690
if ((OP1_INFO() & MAY_BE_ANY) != MAY_BE_LONG
3691-
|| (OP1_INFO() & MAY_BE_ANY) != MAY_BE_LONG) {
3691+
|| (OP2_INFO() & MAY_BE_ANY) != MAY_BE_LONG) {
36923692
return;
36933693
}
36943694

‎ext/opcache/tests/jit/cmp_010.phpt‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--TEST--
2+
JIT CMP: 010 Integer range must not be narrowed by a comparison with a non-integer operand
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit=tracing
8+
opcache.jit_hot_func=1
9+
opcache.jit_hot_loop=1
10+
opcache.jit_hot_return=1
11+
opcache.jit_hot_side_exit=1
12+
--EXTENSIONS--
13+
opcache
14+
--SKIPIF--
15+
<?php
16+
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
17+
?>
18+
--FILE--
19+
<?php
20+
function lt_float(int $x) {
21+
if ($x < 1.0e19) {
22+
return $x + 1;
23+
}
24+
return 0;
25+
}
26+
function lt_string(int $x) {
27+
if ($x < "1e19") {
28+
return $x + 1;
29+
}
30+
return 0;
31+
}
32+
function le_float(int $x) {
33+
if ($x <= -1.0e19) {
34+
return 0;
35+
}
36+
return $x - 1;
37+
}
38+
foreach ([1, 2, 3, PHP_INT_MAX] as $v) {
39+
$r = lt_float($v);
40+
}
41+
echo "int < float: ";
42+
var_dump($r);
43+
foreach ([1, 2, 3, PHP_INT_MAX] as $v) {
44+
$r = lt_string($v);
45+
}
46+
echo "int < numeric string: ";
47+
var_dump($r);
48+
foreach ([1, 2, 3, PHP_INT_MIN] as $v) {
49+
$r = le_float($v);
50+
}
51+
echo "int <= float (false): ";
52+
var_dump($r);
53+
?>
54+
--EXPECT--
55+
int < float: float(9.223372036854776E+18)
56+
int < numeric string: float(9.223372036854776E+18)
57+
int <= float (false): float(-9.223372036854776E+18)

0 commit comments

Comments
 (0)