Skip to content

Commit bf74b39

Browse files
committed
core: Warn when non-representable floats are coerced to int
1 parent 5ae8125 commit bf74b39

26 files changed

+636
-188
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/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+
non-representable float INF was cast to int

Zend/tests/bug39018.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ print "\nDone\n";
6464
--EXPECTF--
6565
Warning: String offset cast occurred in %s on line %d
6666

67+
Warning: non-representable float 1.1111111111111111E+20 was cast to int in %s on line %d
68+
6769
Warning: Uninitialized string offset %d in %s on line %d
6870

6971
Warning: Uninitialized string offset 0 in %s on line %d
@@ -72,10 +74,14 @@ Warning: Uninitialized string offset 0 in %s on line %d
7274

7375
Warning: String offset cast occurred in %s on line %d
7476

77+
Warning: non-representable float -1.1111111111111111E+22 was cast to int in %s on line %d
78+
7579
Warning: Uninitialized string offset %i in %s on line %d
7680

7781
Warning: String offset cast occurred in %s on line %d
7882

83+
Warning: non-representable float -1.1111111111111111E+22 was cast to int in %s on line %d
84+
7985
Warning: Uninitialized string offset %i in %s on line %d
8086

8187
Warning: Uninitialized string offset 0 in %s on line %d

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: non-representable float %f was cast to int
1515
Err: Undefined array key %i
1616
DONE

Zend/tests/int_overflow_64bit.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,14 @@ echo "Done\n";
2424
?>
2525
--EXPECT--
2626
int(9223372036854775807)
27+
28+
Warning: non-representable float %f was cast to int in %s on line %d
2729
int(-9223372036854775808)
30+
31+
Warning: non-representable float %f was cast to int in %s on line %d
2832
int(-9223372036854775808)
33+
34+
Warning: non-representable float %f was cast to int in %s on line %d
2935
int(0)
3036
int(-9223372036854775808)
3137
int(-9223372036854775808)

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: non-representable float %F was cast to int in %s on line %d
139+
140+
Warning: Undefined array key 0 in %s on line %d
141+
NULL
142+
Write:
143+
144+
Warning: non-representable float %F was cast to int in %s on line %d
145+
Read:
146+
147+
Warning: non-representable float %F was cast to int in %s on line %d
148+
int(5)
149+
Read-Write:
150+
151+
Warning: non-representable float %F was cast to int in %s on line %d
152+
isset():
153+
154+
Warning: non-representable float %F was cast to int in %s on line %d
155+
bool(true)
156+
empty():
157+
158+
Warning: non-representable float %F was cast to int in %s on line %d
159+
bool(false)
160+
null coalesce:
161+
162+
Warning: non-representable float %F was cast to int in %s on line %d
163+
int(25)
164+
Reference to dimension:
165+
166+
Warning: non-representable float %F was cast to int 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: non-representable float %F was cast to int in %s on line %d
172+
int(100)
173+
unset():
174+
175+
Warning: non-representable float %F was cast to int in %s on line %d
176+
Nested read:
177+
178+
Warning: non-representable float %F was cast to int 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: non-representable float %F was cast to int in %s on line %d
187+
188+
Warning: non-representable float %F was cast to int in %s on line %d
189+
Nested Read-Write:
190+
191+
Warning: non-representable float %F was cast to int in %s on line %d
192+
193+
Warning: non-representable float %F was cast to int in %s on line %d
194+
Nested isset():
195+
196+
Warning: non-representable float %F was cast to int in %s on line %d
197+
198+
Warning: non-representable float %F was cast to int in %s on line %d
199+
bool(true)
200+
Nested empty():
201+
202+
Warning: non-representable float %F was cast to int in %s on line %d
203+
204+
Warning: non-representable float %F was cast to int in %s on line %d
205+
bool(false)
206+
Nested null coalesce:
207+
208+
Warning: non-representable float %F was cast to int in %s on line %d
209+
210+
Warning: non-representable float %F was cast to int in %s on line %d
211+
int(30)
212+
Nested unset():
213+
214+
Warning: non-representable float %F was cast to int in %s on line %d
215+
216+
Warning: non-representable float %F was cast to int 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

Zend/tests/offsets/array_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: non-representable float %F was cast to int in %s on line %d
139+
140+
Warning: Undefined array key 0 in %s on line %d
141+
NULL
142+
Write:
143+
144+
Warning: non-representable float %F was cast to int in %s on line %d
145+
Read:
146+
147+
Warning: non-representable float %F was cast to int in %s on line %d
148+
int(5)
149+
Read-Write:
150+
151+
Warning: non-representable float %F was cast to int in %s on line %d
152+
isset():
153+
154+
Warning: non-representable float %F was cast to int in %s on line %d
155+
bool(true)
156+
empty():
157+
158+
Warning: non-representable float %F was cast to int in %s on line %d
159+
bool(false)
160+
null coalesce:
161+
162+
Warning: non-representable float %F was cast to int in %s on line %d
163+
int(25)
164+
Reference to dimension:
165+
166+
Warning: non-representable float %F was cast to int 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: non-representable float %F was cast to int in %s on line %d
172+
int(100)
173+
unset():
174+
175+
Warning: non-representable float %F was cast to int in %s on line %d
176+
Nested read:
177+
178+
Warning: non-representable float %F was cast to int 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: non-representable float %F was cast to int in %s on line %d
187+
188+
Warning: non-representable float %F was cast to int in %s on line %d
189+
Nested Read-Write:
190+
191+
Warning: non-representable float %F was cast to int in %s on line %d
192+
193+
Warning: non-representable float %F was cast to int in %s on line %d
194+
Nested isset():
195+
196+
Warning: non-representable float %F was cast to int in %s on line %d
197+
198+
Warning: non-representable float %F was cast to int in %s on line %d
199+
bool(true)
200+
Nested empty():
201+
202+
Warning: non-representable float %F was cast to int in %s on line %d
203+
204+
Warning: non-representable float %F was cast to int in %s on line %d
205+
bool(false)
206+
Nested null coalesce:
207+
208+
Warning: non-representable float %F was cast to int in %s on line %d
209+
210+
Warning: non-representable float %F was cast to int in %s on line %d
211+
int(30)
212+
Nested unset():
213+
214+
Warning: non-representable float %F was cast to int in %s on line %d
215+
216+
Warning: non-representable float %F was cast to int 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
@@ -356,6 +443,7 @@ foreach ($offsets as $dimension) {
356443
!preg_match($EXPECTED_OUTPUT_VALID_OFFSETS_REGEX, $varOutput)
357444
&& !preg_match($EXPECTED_OUTPUT_INVALID_OFFSETS_REGEX, $varOutput)
358445
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OFFSETS_REGEX, $varOutput)
446+
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OOB_OFFSETS_REGEX, $varOutput)
359447
&& !preg_match($EXPECTED_OUTPUT_NULL_OFFSETS_REGEX, $varOutput)
360448
&& $varOutput !== EXPECTED_OUTPUT_RESOURCE_STDERR_OFFSETS
361449
) {
@@ -384,6 +472,7 @@ foreach ($offsets as $offset) {
384472
!preg_match($EXPECTED_OUTPUT_VALID_OFFSETS_REGEX, $varOutput)
385473
&& !preg_match($EXPECTED_OUTPUT_INVALID_OFFSETS_REGEX, $varOutput)
386474
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OFFSETS_REGEX, $varOutput)
475+
&& !preg_match($EXPECTED_OUTPUT_FLOAT_OOB_OFFSETS_REGEX, $varOutput)
387476
&& !preg_match($EXPECTED_OUTPUT_NULL_OFFSETS_REGEX, $varOutput)
388477
&& $varOutput !== EXPECTED_OUTPUT_RESOURCE_STDERR_OFFSETS
389478
) {
File renamed without changes.

Zend/tests/array_offset_002.phpt renamed to Zend/tests/offsets/array_offset_002.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ x($y);
1313
var_dump($y);
1414
?>
1515
--EXPECT--
16-
Err: Implicit conversion from float 1.0E+20 to int loses precision
16+
Err: non-representable float 1.0E+20 was cast to int
1717
array(0) {
1818
}

0 commit comments

Comments
 (0)