Skip to content

Commit b4ed215

Browse files
authored
core: Warn when non-representable floats are coerced to int (#19760)
RFC: https://wiki.php.net/rfc/warnings-php-8-5#casting_out_of_range_floats_to_int
1 parent 5f00673 commit b4ed215

File tree

62 files changed

+1107
-275
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1107
-275
lines changed

Zend/Optimizer/sccp.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ static inline zend_result fetch_array_elem(zval **result, zval *op1, zval *op2)
371371
*result = zend_hash_index_find(Z_ARR_P(op1), Z_LVAL_P(op2));
372372
return SUCCESS;
373373
case IS_DOUBLE: {
374-
zend_long lval = zend_dval_to_lval(Z_DVAL_P(op2));
374+
zend_long lval = zend_dval_to_lval_silent(Z_DVAL_P(op2));
375375
if (!zend_is_long_compatible(Z_DVAL_P(op2), lval)) {
376376
return FAILURE;
377377
}
@@ -459,7 +459,7 @@ static inline zend_result ct_eval_del_array_elem(zval *result, const zval *key)
459459
zend_hash_index_del(Z_ARR_P(result), Z_LVAL_P(key));
460460
break;
461461
case IS_DOUBLE: {
462-
zend_long lval = zend_dval_to_lval(Z_DVAL_P(key));
462+
zend_long lval = zend_dval_to_lval_silent(Z_DVAL_P(key));
463463
if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
464464
return FAILURE;
465465
}
@@ -504,7 +504,7 @@ static inline zend_result ct_eval_add_array_elem(zval *result, zval *value, cons
504504
value = zend_hash_index_update(Z_ARR_P(result), Z_LVAL_P(key), value);
505505
break;
506506
case IS_DOUBLE: {
507-
zend_long lval = zend_dval_to_lval(Z_DVAL_P(key));
507+
zend_long lval = zend_dval_to_lval_silent(Z_DVAL_P(key));
508508
if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
509509
return FAILURE;
510510
}

Zend/Optimizer/zend_inference.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5283,6 +5283,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
52835283
case ZEND_CAST:
52845284
switch (opline->extended_value) {
52855285
case IS_LONG:
5286+
return (t1 & (MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT));
52865287
case IS_DOUBLE:
52875288
return (t1 & MAY_BE_OBJECT);
52885289
case IS_STRING:

Zend/tests/bitwise_not_precision_exception.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ try {
1212
}
1313
?>
1414
--EXPECT--
15-
Implicit conversion from float INF to int loses precision
15+
The float INF is not representable as an int, cast occurred

Zend/tests/bug46701.phpt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ new foo;
2727

2828
?>
2929
--EXPECTF--
30-
Deprecated: Implicit conversion from float 3428599296 to int loses precision in %s on line %d
30+
Warning: The float 3428599296 is not representable as an int, cast occurred in %s on line %d
3131

32-
Deprecated: Implicit conversion from float 3459455488 to int loses precision in %s on line %d
32+
Warning: The float 3459455488 is not representable as an int, cast occurred in %s on line %d
3333

34-
Deprecated: Implicit conversion from float 3459616768 to int loses precision in %s on line %d
34+
Warning: The float 3459616768 is not representable as an int, cast occurred in %s on line %d
3535
array(3) {
3636
[-866368000]=>
3737
int(1)
@@ -41,10 +41,10 @@ array(3) {
4141
int(3)
4242
}
4343

44-
Deprecated: Implicit conversion from float 3459455488 to int loses precision in %s on line %d
44+
Warning: The float 3459455488 is not representable as an int, cast occurred in %s on line %d
4545
int(2)
4646

47-
Deprecated: Implicit conversion from float 3459616768 to int loses precision in %s on line %d
47+
Warning: The float 3459616768 is not representable as an int, cast occurred in %s on line %d
4848
array(1) {
4949
[-835350528]=>
5050
int(3)

Zend/tests/bug78340.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class lib {
3232

3333
function stream_stat() {
3434
return [
35-
'dev' => 3632233996,
35+
'dev' => PHP_INT_MAX,
3636
'size' => strlen($this->bytes),
3737
'ino' => $this->ino
3838
];

Zend/tests/falsetoarray_003.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ $a=[];
1111
?>
1212
DONE
1313
--EXPECTF--
14-
Err: Implicit conversion from float %f to int loses precision
14+
Err: The float %f is not representable as an int, cast occurred
1515
Err: Undefined array key %i
1616
DONE

Zend/tests/int_overflow_32bit.phpt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,19 @@ foreach ($doubles as $d) {
2020

2121
echo "Done\n";
2222
?>
23-
--EXPECT--
23+
--EXPECTF--
24+
Warning: The float 2147483648 is not representable as an int, cast occurred in %s on line %d
2425
int(-2147483648)
26+
27+
Warning: The float 2147483649 is not representable as an int, cast occurred in %s on line %d
2528
int(-2147483647)
29+
30+
Warning: The float 2147483658 is not representable as an int, cast occurred in %s on line %d
2631
int(-2147483638)
32+
33+
Warning: The float 2147483748 is not representable as an int, cast occurred in %s on line %d
2734
int(-2147483548)
35+
36+
Warning: The float 2147484648 is not representable as an int, cast occurred in %s on line %d
2837
int(-2147482648)
2938
Done

Zend/tests/int_overflow_64bit.phpt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,16 @@ foreach ($doubles as $d) {
2222

2323
echo "Done\n";
2424
?>
25-
--EXPECT--
25+
--EXPECTF--
2626
int(9223372036854775807)
27+
28+
Warning: The float %f is not representable as an int, cast occurred in %s on line %d
2729
int(-9223372036854775808)
30+
31+
Warning: The float %f is not representable as an int, cast occurred in %s on line %d
2832
int(-9223372036854775808)
33+
34+
Warning: The float %f is not representable as an int, cast occurred in %s on line %d
2935
int(0)
3036
int(-9223372036854775808)
3137
int(-9223372036854775808)

Zend/tests/int_underflow_32bit.phpt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,18 @@ foreach ($doubles as $d) {
2020

2121
echo "Done\n";
2222
?>
23-
--EXPECT--
23+
--EXPECTF--
2424
int(-2147483648)
25+
26+
Warning: The float -2147483649 is not representable as an int, cast occurred in %s on line %d
2527
int(2147483647)
28+
29+
Warning: The float -2147483658 is not representable as an int, cast occurred in %s on line %d
2630
int(2147483638)
31+
32+
Warning: The float -2147483748 is not representable as an int, cast occurred in %s on line %d
2733
int(2147483548)
34+
35+
Warning: The float -2147484648 is not representable as an int, cast occurred in %s on line %d
2836
int(2147482648)
2937
Done

Zend/tests/offsets/ArrayObject_container_offset_behaviour.phpt

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,93 @@ OUTPUT;
132132

133133
$EXPECTED_OUTPUT_FLOAT_OFFSETS_REGEX = '/^' . expectf_to_regex(EXPECTF_OUTPUT_FLOAT_OFFSETS) . '$/s';
134134

135+
const EXPECTF_OUTPUT_FLOAT_OOB_OFFSETS = <<<OUTPUT
136+
Read before write:
137+
138+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
139+
140+
Warning: Undefined array key 0 in %s on line %d
141+
NULL
142+
Write:
143+
144+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
145+
Read:
146+
147+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
148+
int(5)
149+
Read-Write:
150+
151+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
152+
isset():
153+
154+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
155+
bool(true)
156+
empty():
157+
158+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
159+
bool(false)
160+
null coalesce:
161+
162+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
163+
int(25)
164+
Reference to dimension:
165+
166+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
167+
Value of reference:
168+
int(25)
169+
Value of container dimension after write to reference (should be int(100) if successful):
170+
171+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
172+
int(100)
173+
unset():
174+
175+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
176+
Nested read:
177+
178+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
179+
180+
Warning: Undefined array key 0 in %s on line %d
181+
182+
Warning: Trying to access array offset on null in %s on line 74
183+
NULL
184+
Nested write:
185+
186+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
187+
188+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
189+
Nested Read-Write:
190+
191+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
192+
193+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
194+
Nested isset():
195+
196+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
197+
198+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
199+
bool(true)
200+
Nested empty():
201+
202+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
203+
204+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
205+
bool(false)
206+
Nested null coalesce:
207+
208+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
209+
210+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
211+
int(30)
212+
Nested unset():
213+
214+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
215+
216+
Warning: The float %F is not representable as an int, cast occurred in %s on line %d
217+
218+
OUTPUT;
219+
220+
$EXPECTED_OUTPUT_FLOAT_OOB_OFFSETS_REGEX = '/^' . expectf_to_regex(EXPECTF_OUTPUT_FLOAT_OOB_OFFSETS) . '$/s';
221+
135222
const EXPECTED_OUTPUT_NULL_OFFSETS = <<<OUTPUT
136223
Read before write:
137224
@@ -452,6 +539,7 @@ foreach ($offsets as $dimension) {
452539
!preg_match($EXPECTED_OUTPUT_VALID_OFFSETS_REGEX, $varOutput)
453540
&& !preg_match($EXPECTED_OUTPUT_INVALID_OFFSETS_REGEX, $varOutput)
454541
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OFFSETS_REGEX, $varOutput)
542+
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OOB_OFFSETS_REGEX, $varOutput)
455543
&& !preg_match($EXPECTED_OUTPUT_NULL_OFFSETS_REGEX, $varOutput)
456544
&& $varOutput !== EXPECTED_OUTPUT_NULL_OFFSET
457545
&& $varOutput !== EXPECTED_OUTPUT_RESOURCE_STDERR_OFFSETS
@@ -484,6 +572,7 @@ foreach ($offsets as $offset) {
484572
!preg_match($EXPECTED_OUTPUT_VALID_OFFSETS_REGEX, $varOutput)
485573
&& !preg_match($EXPECTED_OUTPUT_INVALID_OFFSETS_REGEX, $varOutput)
486574
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OFFSETS_REGEX, $varOutput)
575+
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OOB_OFFSETS_REGEX, $varOutput)
487576
&& !preg_match($EXPECTED_OUTPUT_NULL_OFFSETS_REGEX, $varOutput)
488577
&& $varOutput !== EXPECTED_OUTPUT_NULL_OFFSET
489578
&& $varOutput !== EXPECTED_OUTPUT_RESOURCE_STDERR_OFFSETS

0 commit comments

Comments
 (0)