Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 320fe29

Browse files
committed
core: Warn when coercing NAN to other types
RFC: https://wiki.php.net/rfc/warnings-php-8-5#coercing_nan_to_other_types Closes GH-19573
1 parent d27e1e1 commit 320fe29

File tree

45 files changed

+697
-110
lines changed

Some content is hidden

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

45 files changed

+697
-110
lines changed

‎NEWS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ PHP NEWS
1717
(nielsdos)
1818
. Casting floats that are not representable as ints now emits a warning.
1919
(Girgias)
20+
. Casting NAN to other types now emits a warning. (Girgias)
2021

2122
- Bz2:
2223
. Fixed bug GH-19810 (Broken bzopen() stream mode validation). (ilutov)

‎UPGRADING‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ PHP 8.5 UPGRADE NOTES
5959
floats) to int if they cannot be represented as one. This affects explicit
6060
int casts and implicit int casts.
6161
RFC: https://wiki.php.net/rfc/warnings-php-8-5#casting_out_of_range_floats_to_int
62+
. A warning is now emitted when casting NAN to other types.
63+
RFC: https://wiki.php.net/rfc/warnings-php-8-5#coercing_nan_to_other_types
6264

6365
- BZ2:
6466
. bzcompress() now throws a ValueError when $block_size is not between

‎Zend/Optimizer/block_pass.c‎

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -436,18 +436,11 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
436436
Tsource[VAR_NUM(opline->op1.var)] = NULL;
437437
break;
438438
}
439-
ZEND_FALLTHROUGH;
440-
441-
case ZEND_IS_EQUAL:
442-
case ZEND_IS_NOT_EQUAL:
443439
if (opline->op1_type == IS_CONST &&
444440
opline->op2_type == IS_CONST) {
445441
goto optimize_constant_binary_op;
446442
}
447-
/* IS_EQ(TRUE, X) => BOOL(X)
448-
* IS_EQ(FALSE, X) => BOOL_NOT(X)
449-
* IS_NOT_EQ(TRUE, X) => BOOL_NOT(X)
450-
* IS_NOT_EQ(FALSE, X) => BOOL(X)
443+
/*
451444
* CASE(TRUE, X) => BOOL(X)
452445
* CASE(FALSE, X) => BOOL_NOT(X)
453446
*/
@@ -478,6 +471,21 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
478471
goto optimize_bool;
479472
}
480473
break;
474+
475+
case ZEND_IS_EQUAL:
476+
case ZEND_IS_NOT_EQUAL:
477+
if (opline->op1_type == IS_CONST &&
478+
opline->op2_type == IS_CONST) {
479+
goto optimize_constant_binary_op;
480+
}
481+
/* IS_EQ(TRUE, X) => BOOL(X)
482+
* IS_EQ(FALSE, X) => BOOL_NOT(X)
483+
* IS_NOT_EQ(TRUE, X) => BOOL_NOT(X)
484+
* IS_NOT_EQ(FALSE, X) => BOOL(X)
485+
* Those optimizations are not safe if the other operand ends up being NAN
486+
* as BOOL/BOOL_NOT will warn, while IS_EQUAL/IS_NOT_EQUAL do not.
487+
*/
488+
break;
481489
case ZEND_IS_IDENTICAL:
482490
if (opline->op1_type == IS_CONST &&
483491
opline->op2_type == IS_CONST) {

‎Zend/Optimizer/sccp.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ static inline zend_result ct_eval_bool_cast(zval *result, zval *op) {
335335
ZVAL_TRUE(result);
336336
return SUCCESS;
337337
}
338+
/* NAN warns when casting */
339+
if (Z_TYPE_P(op) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op))) {
340+
return FAILURE;
341+
}
338342

339343
ZVAL_BOOL(result, zend_is_true(op));
340344
return SUCCESS;

‎Zend/Optimizer/zend_inference.c‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5109,14 +5109,16 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
51095109
case ZEND_PRE_DEC:
51105110
case ZEND_POST_DEC:
51115111
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5112-
case ZEND_BOOL_NOT:
51135112
case ZEND_JMPZ:
51145113
case ZEND_JMPNZ:
51155114
case ZEND_JMPZ_EX:
51165115
case ZEND_JMPNZ_EX:
5117-
case ZEND_BOOL:
51185116
case ZEND_JMP_SET:
51195117
return (t1 & MAY_BE_OBJECT);
5118+
case ZEND_BOOL:
5119+
case ZEND_BOOL_NOT:
5120+
/* NAN Cast to bool will warn, but if we have a range it is fine */
5121+
return (t1 & MAY_BE_OBJECT) || ((t1 & MAY_BE_DOUBLE) && !OP1_HAS_RANGE());
51205122
case ZEND_BOOL_XOR:
51215123
return (t1 & MAY_BE_OBJECT) || (t2 & MAY_BE_OBJECT);
51225124
case ZEND_IS_EQUAL:

‎Zend/Optimizer/zend_optimizer.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ zend_result zend_optimizer_eval_unary_op(zval *result, uint8_t opcode, zval *op1
7474
}
7575
return unary_op(result, op1);
7676
} else { /* ZEND_BOOL */
77+
if (Z_TYPE_P(op1) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op1))) {
78+
return FAILURE;
79+
}
7780
ZVAL_BOOL(result, zend_is_true(op1));
7881
return SUCCESS;
7982
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Checking NAN in a switch statement with true/false
3+
--FILE--
4+
<?php
5+
6+
$nan = fdiv(0, 0);
7+
switch ($nan) {
8+
case true:
9+
echo "true";
10+
break;
11+
case false:
12+
echo "false";
13+
break;
14+
}
15+
?>
16+
--EXPECT--
17+
true

‎Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn.phpt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ foreach($values as $value) {
2626

2727
?>
2828
--EXPECTF--
29+
Warning: unexpected NAN value was coerced to string in %s on line %d
2930
int(3)
3031
int(3)
3132

‎Zend/tests/type_coercion/float_to_int/explicit_casts_should_not_warn_32bit.phpt‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Explicit (int) cast must not warn 32bit variation
2+
Explicit (int) cast must not warn if value is representable 32bit variation
33
--SKIPIF--
44
<?php
55
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
@@ -26,6 +26,7 @@ foreach($values as $value) {
2626

2727
?>
2828
--EXPECTF--
29+
Warning: unexpected NAN value was coerced to string in %s on line %d
2930
int(3)
3031
int(3)
3132

‎Zend/tests/type_coercion/float_to_int/union_int_string_type_arg.phpt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ int(1)
2323

2424
Deprecated: Implicit conversion from float 1.5 to int loses precision in %s on line %d
2525
int(1)
26+
27+
Warning: unexpected NAN value was coerced to string in %s on line %d
2628
string(3) "NAN"
2729
string(8) "1.0E+121"
2830
string(3) "INF"

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /