Skip to content

[RFC] Warn on implicit float to int conversions. #6661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 61 commits into from
May 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
a70ae1b
Warn on implicit float to int conversions.
Girgias Feb 2, 2021
6a0ddf8
Fix JIT
Girgias Feb 20, 2021
48e3aca
Fix double deprecation notice in debug builds
Girgias Feb 20, 2021
f9be93d
Fix test
Girgias Feb 20, 2021
74ab99c
Remove some ZPP checks
Girgias Feb 20, 2021
4963bf3
Add incompatible float to deprecation message
Girgias Mar 20, 2021
d9f5730
Micro optimization
Girgias Apr 5, 2021
342252b
Add test for negative 0
Girgias Apr 5, 2021
e411fa4
Fix more tests
Girgias Apr 5, 2021
d27a94f
Keep zval_get_long() similar to an (int) cast
Girgias Apr 13, 2021
20dafcc
Rework is_long_compatible function
Girgias Apr 13, 2021
139aa8f
Move SEPARATE_ARRAY below the check.
Girgias Apr 17, 2021
f319fe4
Flip is_lax to is_strict
Girgias Apr 17, 2021
0d678bf
Make sprintf family of functions warn on incompatible float to int co…
Girgias Apr 17, 2021
d2ee140
intval() is like (int) cast
Girgias Apr 17, 2021
8bacb86
Fix jit with incompatible float to long for isset
Girgias Apr 17, 2021
f226954
Extract float to int deprecation message into own function
Girgias Apr 17, 2021
4913890
Rephrase deprecation message
Girgias Apr 17, 2021
f55772b
Use zend_error_unchecked() for deprecation message
Girgias Apr 19, 2021
e78f0ee
Use common function once more
Girgias Apr 19, 2021
737c674
ct_eval should not emit notices
Girgias Apr 19, 2021
fbbb5e4
Fix some tests
Girgias Apr 19, 2021
77c4f5b
Add a ZEND_API for linking
Girgias Apr 20, 2021
6b23056
Fix compile time evaluation
Girgias Apr 20, 2021
bb5a746
Remove error_reporting after fixing compile time eval
Girgias Apr 20, 2021
f50f497
Fix test heading
Girgias Apr 20, 2021
c922dc9
Bailout if array key is float
Girgias Apr 20, 2021
d3ed467
Standardize error message for float-strings
Girgias Apr 20, 2021
443a1d4
Clarify why we need to use (uint32_t)-1 and not 0
Girgias Apr 20, 2021
37e04d2
Fix Win test
Girgias Apr 20, 2021
61e3f94
Bit op and mod may throw
Girgias Apr 26, 2021
8854e74
Fix inference of zend_may_throw
Girgias Apr 26, 2021
25e46f1
Attempt to fix JIT
Girgias Apr 26, 2021
f739178
Revert "Attempt to fix JIT"
Girgias Apr 26, 2021
af16894
Make printf() test not spit random bytes to debug on 32bits
Girgias Apr 28, 2021
02fbb29
Update test after fix in core
Girgias Apr 28, 2021
017bb20
Fix more 32bits tests
Girgias Apr 28, 2021
45b68b6
Revert test change from 32bit
Girgias May 18, 2021
fad5644
Fix pass optimizer
Girgias May 18, 2021
eae1e65
Optimizer fixes and partial revert
Girgias May 18, 2021
fee33db
Fix zend_is_long_compatible arg order
nikic May 18, 2021
261eae0
Add ZEND_COLD'
Girgias May 27, 2021
91784e2
Drop TODOs or handle exception
Girgias May 27, 2021
4e94989
Typo
Girgias May 27, 2021
36ee18e
Add zend_is_op_long_compatible() function instead of repeating the ch…
Girgias May 27, 2021
c43412e
Revert "Revert test change from 32bit"
Girgias May 27, 2021
da449b6
Use a lower float value
Girgias May 27, 2021
843e7f1
Hopefully fix Win test
Girgias May 27, 2021
de37806
Move IS_ARRAY check to is_op_long_compatible
Girgias May 29, 2021
95eae55
Remove redundant parens
Girgias May 29, 2021
8befb02
Remove obsolete TODO comment
Girgias May 29, 2021
da2d7cf
Cast to string instead of int in mysqli test
Girgias May 29, 2021
3fe7801
Amend array tests
Girgias May 29, 2021
e8c1c45
Revert printf changes (do not warn)
Girgias May 29, 2021
c536d4d
Fix test
Girgias May 29, 2021
de5fe1d
Drop TODO comment
Girgias May 29, 2021
d4e1f8e
Fixup after %0 specifier has been introduced for null bytes in run-test
Girgias May 31, 2021
473e14c
Revert changes to formatted_print.c
Girgias May 31, 2021
3f030bf
Drop useless test
Girgias May 31, 2021
ac925c4
Drop printf test changes
Girgias May 31, 2021
09a8044
Fix copy/paste mistake from 32bit to 64bit tests in math tests
Girgias May 31, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Zend/Optimizer/pass1.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} else if (opline->extended_value == ZEND_MOD
|| opline->extended_value == ZEND_SL
|| opline->extended_value == ZEND_SR) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
/* don't optimize if it should produce a runtime numeric string error */
if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
&& !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
convert_to_long(&ZEND_OP2_LITERAL(opline));
zval *op2 = &ZEND_OP2_LITERAL(opline);
if (Z_TYPE_P(op2) != IS_LONG) {
if (!zend_is_op_long_compatible(op2)) {
break;
}
convert_to_long(op2);
}
} else if (opline->extended_value == ZEND_CONCAT) {
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
Expand Down
27 changes: 21 additions & 6 deletions Zend/Optimizer/sccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,14 @@ static inline int fetch_array_elem(zval **result, zval *op1, zval *op2) {
case IS_LONG:
*result = zend_hash_index_find(Z_ARR_P(op1), Z_LVAL_P(op2));
return SUCCESS;
case IS_DOUBLE:
*result = zend_hash_index_find(Z_ARR_P(op1), zend_dval_to_lval(Z_DVAL_P(op2)));
case IS_DOUBLE: {
zend_long lval = zend_dval_to_lval(Z_DVAL_P(op2));
if (!zend_is_long_compatible(Z_DVAL_P(op2), lval)) {
return FAILURE;
}
*result = zend_hash_index_find(Z_ARR_P(op1), lval);
return SUCCESS;
}
case IS_STRING:
*result = zend_symtable_find(Z_ARR_P(op1), Z_STR_P(op2));
return SUCCESS;
Expand Down Expand Up @@ -508,9 +513,14 @@ static inline int ct_eval_del_array_elem(zval *result, zval *key) {
case IS_LONG:
zend_hash_index_del(Z_ARR_P(result), Z_LVAL_P(key));
break;
case IS_DOUBLE:
zend_hash_index_del(Z_ARR_P(result), zend_dval_to_lval(Z_DVAL_P(key)));
case IS_DOUBLE: {
zend_long lval = zend_dval_to_lval(Z_DVAL_P(key));
if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
return FAILURE;
}
zend_hash_index_del(Z_ARR_P(result), lval);
break;
}
case IS_STRING:
zend_symtable_del(Z_ARR_P(result), Z_STR_P(key));
break;
Expand Down Expand Up @@ -548,11 +558,16 @@ static inline int ct_eval_add_array_elem(zval *result, zval *value, zval *key) {
SEPARATE_ARRAY(result);
value = zend_hash_index_update(Z_ARR_P(result), Z_LVAL_P(key), value);
break;
case IS_DOUBLE:
case IS_DOUBLE: {
zend_long lval = zend_dval_to_lval(Z_DVAL_P(key));
if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
return FAILURE;
}
SEPARATE_ARRAY(result);
value = zend_hash_index_update(
Z_ARR_P(result), zend_dval_to_lval(Z_DVAL_P(key)), value);
Z_ARR_P(result), lval, value);
break;
}
case IS_STRING:
SEPARATE_ARRAY(result);
value = zend_symtable_update(Z_ARR_P(result), Z_STR_P(key), value);
Expand Down
19 changes: 13 additions & 6 deletions Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -4481,7 +4481,6 @@ ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op,
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
case ZEND_DIV:
case ZEND_MOD:
if (!OP2_HAS_RANGE() ||
(OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
/* Division by zero */
Expand All @@ -4493,10 +4492,18 @@ ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op,
case ZEND_POW:
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
/* Ops may throw if not an integer */
case ZEND_MOD:
if (!OP2_HAS_RANGE() ||
(OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
/* Division by zero */
return 1;
}
ZEND_FALLTHROUGH;
case ZEND_SL:
case ZEND_SR:
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
(t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
!OP2_HAS_RANGE() ||
OP2_MIN_RANGE() < 0;
case ZEND_CONCAT:
Expand All @@ -4510,10 +4517,10 @@ ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op,
&& (t2 & MAY_BE_ANY) == MAY_BE_STRING) {
return 0;
}
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
(t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
case ZEND_BW_NOT:
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
case ZEND_PRE_INC:
case ZEND_POST_INC:
case ZEND_PRE_DEC:
Expand Down
4 changes: 4 additions & 0 deletions Zend/tests/array_offset.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ echo "Done\n";
--EXPECTF--
Warning: Undefined array key -1 in %s on line %d

Deprecated: Implicit conversion from non-compatible float -1.1 to int in %s on line %d

Warning: Undefined array key -1 in %s on line %d

Warning: Undefined array key -1 in %s on line %d

Deprecated: Implicit conversion from non-compatible float -1.1 to int in %s on line %d

Warning: Undefined array key -1 in %s on line %d
Done
11 changes: 10 additions & 1 deletion Zend/tests/bug46701.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ class foo {
new foo;

?>
--EXPECT--
--EXPECTF--
Deprecated: Implicit conversion from non-compatible float 3428599296 to int in %s on line %d

Deprecated: Implicit conversion from non-compatible float 3459455488 to int in %s on line %d

Deprecated: Implicit conversion from non-compatible float 3459616768 to int in %s on line %d
array(3) {
[-866368000]=>
int(1)
Expand All @@ -35,7 +40,11 @@ array(3) {
[-835350528]=>
int(3)
}

Deprecated: Implicit conversion from non-compatible float 3459455488 to int in %s on line %d
int(2)

Deprecated: Implicit conversion from non-compatible float 3459616768 to int in %s on line %d
array(1) {
[-835350528]=>
int(3)
Expand Down
3 changes: 2 additions & 1 deletion Zend/tests/bug72347.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ function test() : int {
}
var_dump(test());
?>
--EXPECT--
--EXPECTF--
Deprecated: Implicit conversion from non-compatible float 1.5 to int in %s on line %d
float(1.5)
int(1)
2 changes: 2 additions & 0 deletions Zend/tests/constant_expressions_dynamic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ var_dump(
?>
--EXPECTF--
Warning: A non-numeric value encountered in %s on line %d

Deprecated: Implicit conversion from non-compatible float 3.14 to int in %s on line %d
int(3)
string(4) "1foo"
bool(false)
Expand Down
20 changes: 19 additions & 1 deletion Zend/tests/empty_str_offset.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ var_dump(empty($str[$f]));
print "done\n";

?>
--EXPECT--
--EXPECTF--
- empty ---
bool(false)
bool(true)
Expand Down Expand Up @@ -98,14 +98,32 @@ bool(true)
- null ---
bool(false)
- double ---

Deprecated: Implicit conversion from non-compatible float -1.1 to int in %s on line %d
bool(false)

Deprecated: Implicit conversion from non-compatible float -10.5 to int in %s on line %d
bool(true)

Deprecated: Implicit conversion from non-compatible float -4.1 to int in %s on line %d
bool(true)

Deprecated: Implicit conversion from non-compatible float -0.8 to int in %s on line %d
bool(false)

Deprecated: Implicit conversion from non-compatible float -0.1 to int in %s on line %d
bool(false)

Deprecated: Implicit conversion from non-compatible float 0.2 to int in %s on line %d
bool(false)

Deprecated: Implicit conversion from non-compatible float 0.9 to int in %s on line %d
bool(false)

Deprecated: Implicit conversion from non-compatible float 3.141592653589793 to int in %s on line %d
bool(false)

Deprecated: Implicit conversion from non-compatible float 100.5001 to int in %s on line %d
bool(true)
- array ---
bool(true)
Expand Down
38 changes: 38 additions & 0 deletions Zend/tests/float_to_int/explicit_casts_should_not_warn.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
--TEST--
Explicit (int) cast must not warn
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
?>
--FILE--
<?php

$values =[
3.0,
3.5,
10e120,
10e300,
fdiv(0, 0),
(string) 3.0,
(string) 3.5,
(string) 10e120,
(string) 10e300,
(string) fdiv(0, 0),
];

foreach($values as $value) {
var_dump((int) $value);
}

?>
--EXPECT--
int(3)
int(3)
int(0)
int(0)
int(0)
int(3)
int(3)
int(9223372036854775807)
int(9223372036854775807)
int(0)
38 changes: 38 additions & 0 deletions Zend/tests/float_to_int/explicit_casts_should_not_warn_32bit.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
--TEST--
Explicit (int) cast must not warn 32bit variation
--SKIPIF--
<?php
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
?>
--FILE--
<?php

$values =[
3.0,
3.5,
10e120,
10e300,
fdiv(0, 0),
(string) 3.0,
(string) 3.5,
(string) 10e120,
(string) 10e300,
(string) fdiv(0, 0),
];

foreach($values as $value) {
var_dump((int) $value);
}

?>
--EXPECT--
int(3)
int(3)
int(0)
int(0)
int(0)
int(3)
int(3)
int(2147483647)
int(2147483647)
int(0)
15 changes: 15 additions & 0 deletions Zend/tests/float_to_int/negative_zero_check.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Negative 0 check
--FILE--
<?php

$negativeZero = -0.0;
var_dump($negativeZero);
var_dump($negativeZero === (float)(int)$negativeZero);
var_dump($negativeZero === 0.0);

?>
--EXPECT--
float(-0)
bool(true)
bool(true)
Loading