Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 21 additions & 3 deletions Zend/Optimizer/dce.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ static inline bool may_have_side_effects(
case ZEND_DIV:
case ZEND_MOD:
case ZEND_BOOL_XOR:
case ZEND_BOOL:
case ZEND_BOOL_NOT:
case ZEND_BW_NOT:
case ZEND_SL:
case ZEND_SR:
Expand All @@ -106,7 +104,6 @@ static inline bool may_have_side_effects(
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_CASE:
case ZEND_CASE_STRICT:
case ZEND_CAST:
case ZEND_ROPE_INIT:
case ZEND_ROPE_ADD:
case ZEND_INIT_ARRAY:
Expand All @@ -126,6 +123,27 @@ static inline bool may_have_side_effects(
case ZEND_ARRAY_KEY_EXISTS:
/* No side effects */
return 0;
case ZEND_CAST: {
uint32_t t1 = OP1_INFO();
/* Cast from NAN emits warning */
if (t1 & MAY_BE_DOUBLE) {
return true;
}
if (t1 & MAY_BE_ARRAY) {
/* Array cast to string emits warning */
return opline->extended_value == IS_STRING;
}
return false;
}
case ZEND_BOOL:
case ZEND_BOOL_NOT: {
uint32_t t1 = OP1_INFO();
/* Cast from NAN emits warning */
if (t1 & MAY_BE_DOUBLE) {
return true;
}
return false;
}
case ZEND_FREE:
return opline->extended_value == ZEND_FREE_VOID_CAST;
case ZEND_ADD_ARRAY_ELEMENT:
Expand Down
4 changes: 4 additions & 0 deletions Zend/Optimizer/sccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,10 @@ static inline zend_result ct_eval_bool_cast(zval *result, zval *op) {
ZVAL_TRUE(result);
return SUCCESS;
}
/* NAN warns when casting */
if (Z_TYPE_P(op) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op))) {
return FAILURE;
}

ZVAL_BOOL(result, zend_is_true(op));
return SUCCESS;
Expand Down
6 changes: 4 additions & 2 deletions Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -5105,14 +5105,16 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
case ZEND_PRE_DEC:
case ZEND_POST_DEC:
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
case ZEND_BOOL_NOT:
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
case ZEND_BOOL:
case ZEND_JMP_SET:
return (t1 & MAY_BE_OBJECT);
case ZEND_BOOL:
case ZEND_BOOL_NOT:
/* NAN Cast to bool will warn */
return (t1 & MAY_BE_OBJECT) || (t1 & MAY_BE_DOUBLE);
case ZEND_BOOL_XOR:
return (t1 & MAY_BE_OBJECT) || (t2 & MAY_BE_OBJECT);
case ZEND_IS_EQUAL:
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/runtime_compile_time_binary_operands.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
?>
--FILE--
<?php
error_reporting(E_ALL ^ E_DEPRECATED);
error_reporting(E_ALL ^ E_DEPRECATED ^ E_WARNING);

$binaryOperators = [
"==",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Explicit (int) cast must not warn
Explicit (int) cast must not warn (except for NAN)
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
Expand All @@ -12,12 +12,10 @@ $values =[
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) {
Expand All @@ -30,9 +28,7 @@ int(3)
int(3)
int(0)
int(0)
int(0)
int(3)
int(3)
int(9223372036854775807)
int(9223372036854775807)
int(0)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Explicit (int) cast must not warn 32bit variation
Explicit (int) cast must not warn (except for NAN) 32bit variation
--SKIPIF--
<?php
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
Expand All @@ -12,12 +12,10 @@ $values =[
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) {
Expand All @@ -30,9 +28,7 @@ int(3)
int(3)
int(0)
int(0)
int(0)
int(3)
int(3)
int(2147483647)
int(2147483647)
int(0)
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ int(1)

Deprecated: Implicit conversion from float 1.5 to int loses precision in %s on line %d
int(1)

Warning: unexpected NAN value was coerced to string in %s on line %d
string(3) "NAN"
string(8) "1.0E+121"
string(3) "INF"
4 changes: 0 additions & 4 deletions Zend/tests/type_coercion/int_special_values.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ $values = [
-INF,
1 / INF,
-1 / INF, // Negative zero,
NAN
];

foreach($values as $value) {
Expand All @@ -32,6 +31,3 @@ int(0)

float(-0)
int(0)

float(NAN)
int(0)
123 changes: 123 additions & 0 deletions Zend/tests/type_coercion/nan_comp_op.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
--TEST--
NAN coerced to other types
--FILE--
<?php

$binaryOperators = [
"==",
"!=",
"===",
"!==",
"<",
"<=",
">",
">=",
"<=>",
];
$inputs = [
0,
null,
false,
true,
"",
[],
NAN,
];

$nan = fdiv(0, 0);
var_dump($nan);
foreach ($inputs as $right) {
echo 'Using ';
var_export($right);
echo ' as right op', PHP_EOL;
var_dump($nan == $right);
var_dump($nan != $right);
var_dump($nan === $right);
var_dump($nan !== $right);
var_dump($nan < $right);
var_dump($nan <= $right);
var_dump($nan > $right);
var_dump($nan >= $right);
var_dump($nan <=> $right);
}

?>
--CLEAN--
<?php
$fl = __DIR__ . DIRECTORY_SEPARATOR . 'compare_binary_operands_nan_temp.php';
@unlink($fl);
?>
--EXPECT--
float(NAN)
Using 0 as right op
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
int(1)
Using NULL as right op
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
int(1)
Using false as right op
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
int(1)
Using true as right op
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
int(1)
Using '' as right op
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
int(1)
Using array (
) as right op
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
int(1)
Using NAN as right op
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
int(1)

93 changes: 93 additions & 0 deletions Zend/tests/type_coercion/nan_to_other.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
--TEST--
NAN coerced to other types
--FILE--
<?php

$nan = fdiv(0, 0);
var_dump($nan);

function implicit_to_bool(bool $v) {
var_dump($v);
}
function implicit_to_string(string $v) {
var_dump($v);
}

implicit_to_bool($nan);
implicit_to_string($nan);

var_dump((int) $nan);
var_dump((bool) $nan);
var_dump((string) $nan);
var_dump((array) $nan);
var_dump((object) $nan);

$types = [
'null',
'bool',
'int',
'string',
'array',
'object',
];

foreach ($types as $type) {
$nan = fdiv(0, 0);
settype($nan, $type);
var_dump($nan);
}

?>
--EXPECTF--
float(NAN)

Warning: unexpected NAN value was coerced to bool in %s on line %d
bool(true)

Warning: unexpected NAN value was coerced to string in %s on line %d
string(3) "NAN"

Warning: unexpected NAN value was coerced to int in %s on line %d
int(0)

Warning: unexpected NAN value was coerced to bool in %s on line %d
bool(true)

Warning: unexpected NAN value was coerced to string in %s on line %d
string(3) "NAN"

Warning: unexpected NAN value was coerced to array in %s on line %d
array(1) {
[0]=>
float(NAN)
}

Warning: unexpected NAN value was coerced to object in %s on line %d
object(stdClass)#%d (1) {
["scalar"]=>
float(NAN)
}

Warning: unexpected NAN value was coerced to null in %s on line %d
NULL

Warning: unexpected NAN value was coerced to bool in %s on line %d
bool(true)

Warning: unexpected NAN value was coerced to int in %s on line %d
int(0)

Warning: unexpected NAN value was coerced to string in %s on line %d
string(3) "NAN"

Warning: unexpected NAN value was coerced to array in %s on line %d
array(1) {
[0]=>
float(NAN)
}

Warning: unexpected NAN value was coerced to object in %s on line %d
object(stdClass)#%d (1) {
["scalar"]=>
float(NAN)
}
Loading
Loading