mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
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
This commit is contained in:
1
NEWS
1
NEWS
@@ -17,6 +17,7 @@ PHP NEWS
|
||||
(nielsdos)
|
||||
. Casting floats that are not representable as ints now emits a warning.
|
||||
(Girgias)
|
||||
. Casting NAN to other types now emits a warning. (Girgias)
|
||||
|
||||
- Bz2:
|
||||
. Fixed bug GH-19810 (Broken bzopen() stream mode validation). (ilutov)
|
||||
|
||||
@@ -59,6 +59,8 @@ PHP 8.5 UPGRADE NOTES
|
||||
floats) to int if they cannot be represented as one. This affects explicit
|
||||
int casts and implicit int casts.
|
||||
RFC: https://wiki.php.net/rfc/warnings-php-8-5#casting_out_of_range_floats_to_int
|
||||
. A warning is now emitted when casting NAN to other types.
|
||||
RFC: https://wiki.php.net/rfc/warnings-php-8-5#coercing_nan_to_other_types
|
||||
|
||||
- BZ2:
|
||||
. bzcompress() now throws a ValueError when $block_size is not between
|
||||
|
||||
@@ -436,18 +436,11 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
|
||||
Tsource[VAR_NUM(opline->op1.var)] = NULL;
|
||||
break;
|
||||
}
|
||||
ZEND_FALLTHROUGH;
|
||||
|
||||
case ZEND_IS_EQUAL:
|
||||
case ZEND_IS_NOT_EQUAL:
|
||||
if (opline->op1_type == IS_CONST &&
|
||||
opline->op2_type == IS_CONST) {
|
||||
goto optimize_constant_binary_op;
|
||||
}
|
||||
/* IS_EQ(TRUE, X) => BOOL(X)
|
||||
* IS_EQ(FALSE, X) => BOOL_NOT(X)
|
||||
* IS_NOT_EQ(TRUE, X) => BOOL_NOT(X)
|
||||
* IS_NOT_EQ(FALSE, X) => BOOL(X)
|
||||
/*
|
||||
* CASE(TRUE, X) => BOOL(X)
|
||||
* CASE(FALSE, X) => BOOL_NOT(X)
|
||||
*/
|
||||
@@ -478,6 +471,21 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
|
||||
goto optimize_bool;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZEND_IS_EQUAL:
|
||||
case ZEND_IS_NOT_EQUAL:
|
||||
if (opline->op1_type == IS_CONST &&
|
||||
opline->op2_type == IS_CONST) {
|
||||
goto optimize_constant_binary_op;
|
||||
}
|
||||
/* IS_EQ(TRUE, X) => BOOL(X)
|
||||
* IS_EQ(FALSE, X) => BOOL_NOT(X)
|
||||
* IS_NOT_EQ(TRUE, X) => BOOL_NOT(X)
|
||||
* IS_NOT_EQ(FALSE, X) => BOOL(X)
|
||||
* Those optimizations are not safe if the other operand ends up being NAN
|
||||
* as BOOL/BOOL_NOT will warn, while IS_EQUAL/IS_NOT_EQUAL do not.
|
||||
*/
|
||||
break;
|
||||
case ZEND_IS_IDENTICAL:
|
||||
if (opline->op1_type == IS_CONST &&
|
||||
opline->op2_type == IS_CONST) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5109,14 +5109,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, but if we have a range it is fine */
|
||||
return (t1 & MAY_BE_OBJECT) || ((t1 & MAY_BE_DOUBLE) && !OP1_HAS_RANGE());
|
||||
case ZEND_BOOL_XOR:
|
||||
return (t1 & MAY_BE_OBJECT) || (t2 & MAY_BE_OBJECT);
|
||||
case ZEND_IS_EQUAL:
|
||||
|
||||
@@ -74,6 +74,9 @@ zend_result zend_optimizer_eval_unary_op(zval *result, uint8_t opcode, zval *op1
|
||||
}
|
||||
return unary_op(result, op1);
|
||||
} else { /* ZEND_BOOL */
|
||||
if (Z_TYPE_P(op1) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op1))) {
|
||||
return FAILURE;
|
||||
}
|
||||
ZVAL_BOOL(result, zend_is_true(op1));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
17
Zend/tests/optimizer/nan_warning_switch.phpt
Normal file
17
Zend/tests/optimizer/nan_warning_switch.phpt
Normal file
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Checking NAN in a switch statement with true/false
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
switch ($nan) {
|
||||
case true:
|
||||
echo "true";
|
||||
break;
|
||||
case false:
|
||||
echo "false";
|
||||
break;
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
true
|
||||
@@ -26,6 +26,7 @@ foreach($values as $value) {
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: unexpected NAN value was coerced to string in %s on line %d
|
||||
int(3)
|
||||
int(3)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
--TEST--
|
||||
Explicit (int) cast must not warn 32bit variation
|
||||
Explicit (int) cast must not warn if value is representable 32bit variation
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
|
||||
@@ -26,6 +26,7 @@ foreach($values as $value) {
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: unexpected NAN value was coerced to string in %s on line %d
|
||||
int(3)
|
||||
int(3)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -40,31 +40,53 @@ foreach ($types as $type) {
|
||||
?>
|
||||
--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: The float NAN is not representable as an int, cast occurred 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: The float NAN is not representable as an int, cast occurred 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)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to array
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = null;
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'array');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to array
|
||||
array(1) {
|
||||
[0]=>
|
||||
NULL
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to array 2
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
unset($nan);
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'array');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to array
|
||||
array(1) {
|
||||
[0]=>
|
||||
float(NAN)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to array 3
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = bin2hex(random_bytes(4));
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'array');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to array
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(8) "%s"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to bool
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = null;
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'bool');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to bool
|
||||
bool(true)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to bool 2
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
unset($nan);
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'bool');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to bool
|
||||
bool(true)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to bool 3
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = bin2hex(random_bytes(4));
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'bool');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to bool
|
||||
bool(true)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to int
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = null;
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'int');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
The float NAN is not representable as an int, cast occurred
|
||||
int(0)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to int 2
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
unset($nan);
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'int');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
The float NAN is not representable as an int, cast occurred
|
||||
int(0)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to int 3
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = bin2hex(random_bytes(4));
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'int');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
The float NAN is not representable as an int, cast occurred
|
||||
int(0)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to null
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = 45;
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'null');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to null
|
||||
NULL
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to null 2
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
unset($nan);
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'null');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to null
|
||||
NULL
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to null 3
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = bin2hex(random_bytes(4));
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'null');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to null
|
||||
NULL
|
||||
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to object
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = null;
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'object');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to object
|
||||
object(stdClass)#2 (1) {
|
||||
["scalar"]=>
|
||||
NULL
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to object 2
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
unset($nan);
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'object');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to object
|
||||
object(stdClass)#2 (1) {
|
||||
["scalar"]=>
|
||||
float(NAN)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to object 3
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = bin2hex(random_bytes(4));
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'object');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to object
|
||||
object(stdClass)#2 (1) {
|
||||
["scalar"]=>
|
||||
string(8) "%s"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to string
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = null;
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'string');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to string
|
||||
string(3) "NAN"
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to string 2
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
unset($nan);
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'string');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to string
|
||||
string(3) "NAN"
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Error handler dtor NAN value, set to string 3
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
global $nan;
|
||||
$nan = [bin2hex(random_bytes(4))];
|
||||
echo $errstr, "\n";
|
||||
});
|
||||
|
||||
$nan = fdiv(0, 0);
|
||||
var_dump($nan);
|
||||
settype($nan, 'string');
|
||||
var_dump($nan);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(NAN)
|
||||
unexpected NAN value was coerced to string
|
||||
string(3) "NAN"
|
||||
@@ -194,6 +194,7 @@ string(0) ""
|
||||
string(%d) "%d"
|
||||
|
||||
*** Trying float(NAN)
|
||||
E_WARNING: unexpected NAN value was coerced to string on line %d
|
||||
string(3) "NAN"
|
||||
|
||||
*** Trying bool(true)
|
||||
@@ -247,6 +248,7 @@ bool(false)
|
||||
bool(true)
|
||||
|
||||
*** Trying float(NAN)
|
||||
E_WARNING: unexpected NAN value was coerced to bool on line %d
|
||||
bool(true)
|
||||
|
||||
*** Trying bool(true)
|
||||
|
||||
@@ -156,6 +156,7 @@ string(0) ""
|
||||
*** Trying int(2147483647)
|
||||
string(10) "2147483647"
|
||||
*** Trying float(NAN)
|
||||
E_WARNING: unexpected NAN value was coerced to string on line %d
|
||||
string(3) "NAN"
|
||||
*** Trying bool(true)
|
||||
string(1) "1"
|
||||
@@ -193,6 +194,7 @@ bool(false)
|
||||
*** Trying int(2147483647)
|
||||
bool(true)
|
||||
*** Trying float(NAN)
|
||||
E_WARNING: unexpected NAN value was coerced to bool on line %d
|
||||
bool(true)
|
||||
*** Trying bool(true)
|
||||
bool(true)
|
||||
|
||||
@@ -156,6 +156,7 @@ string(0) ""
|
||||
*** Trying int(9223372036854775807)
|
||||
string(19) "9223372036854775807"
|
||||
*** Trying float(NAN)
|
||||
E_WARNING: unexpected NAN value was coerced to string on line %d
|
||||
string(3) "NAN"
|
||||
*** Trying bool(true)
|
||||
string(1) "1"
|
||||
@@ -193,6 +194,7 @@ bool(false)
|
||||
*** Trying int(9223372036854775807)
|
||||
bool(true)
|
||||
*** Trying float(NAN)
|
||||
E_WARNING: unexpected NAN value was coerced to bool on line %d
|
||||
bool(true)
|
||||
*** Trying bool(true)
|
||||
bool(true)
|
||||
|
||||
@@ -10046,6 +10046,11 @@ ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, const zval *op)
|
||||
}
|
||||
return Z_TYPE_P(op) <= IS_TRUE || !zend_is_op_long_compatible(op);
|
||||
}
|
||||
/* Can happen when called from zend_optimizer_eval_unary_op() */
|
||||
if (opcode == ZEND_BOOL || opcode == ZEND_BOOL_NOT) {
|
||||
/* ZEND_BOOL/ZEND_BOOL_NOT warns when casting NAN. */
|
||||
return Z_TYPE_P(op) == IS_DOUBLE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -10229,29 +10234,7 @@ static void zend_compile_binary_op(znode *result, zend_ast *ast) /* {{{ */
|
||||
}
|
||||
|
||||
do {
|
||||
if (opcode == ZEND_IS_EQUAL || opcode == ZEND_IS_NOT_EQUAL) {
|
||||
if (left_node.op_type == IS_CONST) {
|
||||
if (Z_TYPE(left_node.u.constant) == IS_FALSE) {
|
||||
opcode = (opcode == ZEND_IS_NOT_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
|
||||
zend_emit_op_tmp(result, opcode, &right_node, NULL);
|
||||
break;
|
||||
} else if (Z_TYPE(left_node.u.constant) == IS_TRUE) {
|
||||
opcode = (opcode == ZEND_IS_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
|
||||
zend_emit_op_tmp(result, opcode, &right_node, NULL);
|
||||
break;
|
||||
}
|
||||
} else if (right_node.op_type == IS_CONST) {
|
||||
if (Z_TYPE(right_node.u.constant) == IS_FALSE) {
|
||||
opcode = (opcode == ZEND_IS_NOT_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
|
||||
zend_emit_op_tmp(result, opcode, &left_node, NULL);
|
||||
break;
|
||||
} else if (Z_TYPE(right_node.u.constant) == IS_TRUE) {
|
||||
opcode = (opcode == ZEND_IS_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
|
||||
zend_emit_op_tmp(result, opcode, &left_node, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (opcode == ZEND_IS_IDENTICAL || opcode == ZEND_IS_NOT_IDENTICAL) {
|
||||
if (opcode == ZEND_IS_IDENTICAL || opcode == ZEND_IS_NOT_IDENTICAL) {
|
||||
/* convert $x === null to is_null($x) (i.e. ZEND_TYPE_CHECK opcode). Do the same thing for false/true. (covers IS_NULL, IS_FALSE, and IS_TRUE) */
|
||||
if (left_node.op_type == IS_CONST) {
|
||||
if (Z_TYPE(left_node.u.constant) <= IS_TRUE && Z_TYPE(left_node.u.constant) >= IS_NULL) {
|
||||
@@ -12058,6 +12041,10 @@ static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t
|
||||
|
||||
bool zend_try_ct_eval_cast(zval *result, uint32_t type, zval *op1)
|
||||
{
|
||||
/* NAN warns when casting */
|
||||
if (UNEXPECTED(Z_TYPE_P(op1) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op1)))) {
|
||||
return false;
|
||||
}
|
||||
switch (type) {
|
||||
case _IS_BOOL:
|
||||
ZVAL_BOOL(result, zval_is_true(op1));
|
||||
|
||||
@@ -234,6 +234,9 @@ static zend_always_inline void zend_cast_zval_to_object(zval *result, zval *expr
|
||||
}
|
||||
Z_OBJ_P(result)->properties = ht;
|
||||
} else if (Z_TYPE_P(expr) != IS_NULL) {
|
||||
if (UNEXPECTED(Z_TYPE_P(expr) == IS_DOUBLE && zend_isnan(Z_DVAL_P(expr)))) {
|
||||
zend_nan_coerced_to_type_warning(IS_OBJECT);
|
||||
}
|
||||
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
|
||||
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
|
||||
if (op1_type == IS_CONST) {
|
||||
@@ -248,6 +251,9 @@ static zend_always_inline void zend_cast_zval_to_array(zval *result, zval *expr,
|
||||
extern zend_class_entry *zend_ce_closure;
|
||||
if (op1_type == IS_CONST || Z_TYPE_P(expr) != IS_OBJECT || Z_OBJCE_P(expr) == zend_ce_closure) {
|
||||
if (Z_TYPE_P(expr) != IS_NULL) {
|
||||
if (UNEXPECTED(Z_TYPE_P(expr) == IS_DOUBLE && zend_isnan(Z_DVAL_P(expr)))) {
|
||||
zend_nan_coerced_to_type_warning(IS_ARRAY);
|
||||
}
|
||||
ZVAL_ARR(result, zend_new_array(1));
|
||||
expr = zend_hash_index_add_new(Z_ARRVAL_P(result), 0, expr);
|
||||
if (op1_type == IS_CONST) {
|
||||
|
||||
@@ -574,9 +574,13 @@ try_again:
|
||||
break;
|
||||
case IS_LONG:
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
ZVAL_LONG(op, zend_dval_to_lval(Z_DVAL_P(op)));
|
||||
case IS_DOUBLE: {
|
||||
/* NAN might emit a warning */
|
||||
zend_long new_value = zend_dval_to_lval(Z_DVAL_P(op));
|
||||
zval_ptr_dtor(op);
|
||||
ZVAL_LONG(op, new_value);
|
||||
break;
|
||||
}
|
||||
case IS_STRING:
|
||||
{
|
||||
zend_string *str = Z_STR_P(op);
|
||||
@@ -672,6 +676,9 @@ try_again:
|
||||
|
||||
ZEND_API void ZEND_FASTCALL convert_to_null(zval *op) /* {{{ */
|
||||
{
|
||||
if (UNEXPECTED(Z_TYPE_P(op) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op)))) {
|
||||
zend_nan_coerced_to_type_warning(IS_NULL);
|
||||
}
|
||||
zval_ptr_dtor(op);
|
||||
ZVAL_NULL(op);
|
||||
}
|
||||
@@ -699,9 +706,16 @@ try_again:
|
||||
case IS_LONG:
|
||||
ZVAL_BOOL(op, Z_LVAL_P(op) ? 1 : 0);
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
ZVAL_BOOL(op, Z_DVAL_P(op) ? 1 : 0);
|
||||
case IS_DOUBLE: {
|
||||
/* We compute the new value before emitting the warning as the zval may change */
|
||||
bool new_value = Z_DVAL_P(op) ? true : false;
|
||||
if (UNEXPECTED(zend_isnan(Z_DVAL_P(op)))) {
|
||||
zend_nan_coerced_to_type_warning(_IS_BOOL);
|
||||
zval_ptr_dtor(op);
|
||||
}
|
||||
ZVAL_BOOL(op, new_value);
|
||||
break;
|
||||
}
|
||||
case IS_STRING:
|
||||
{
|
||||
zend_string *str = Z_STR_P(op);
|
||||
@@ -766,9 +780,13 @@ try_again:
|
||||
case IS_LONG:
|
||||
ZVAL_STR(op, zend_long_to_str(Z_LVAL_P(op)));
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
ZVAL_NEW_STR(op, zend_double_to_str(Z_DVAL_P(op)));
|
||||
case IS_DOUBLE: {
|
||||
/* Casting NAN will cause a warning */
|
||||
zend_string *new_value = zend_double_to_str(Z_DVAL_P(op));
|
||||
zval_ptr_dtor(op);
|
||||
ZVAL_NEW_STR(op, new_value);
|
||||
break;
|
||||
}
|
||||
case IS_ARRAY:
|
||||
zend_error(E_WARNING, "Array to string conversion");
|
||||
zval_ptr_dtor(op);
|
||||
@@ -813,6 +831,9 @@ ZEND_API bool ZEND_FASTCALL _try_convert_to_string(zval *op) /* {{{ */
|
||||
|
||||
static void convert_scalar_to_array(zval *op) /* {{{ */
|
||||
{
|
||||
if (UNEXPECTED(Z_TYPE_P(op) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op)))) {
|
||||
zend_nan_coerced_to_type_warning(IS_ARRAY);
|
||||
}
|
||||
HashTable *ht = zend_new_array(1);
|
||||
zend_hash_index_add_new(ht, 0, op);
|
||||
ZVAL_ARR(op, ht);
|
||||
@@ -895,6 +916,11 @@ try_again:
|
||||
case IS_REFERENCE:
|
||||
zend_unwrap_reference(op);
|
||||
goto try_again;
|
||||
case IS_DOUBLE:
|
||||
if (UNEXPECTED(zend_isnan(Z_DVAL_P(op)))) {
|
||||
zend_nan_coerced_to_type_warning(IS_OBJECT);
|
||||
}
|
||||
ZEND_FALLTHROUGH;
|
||||
default: {
|
||||
zval tmp;
|
||||
ZVAL_COPY_VALUE(&tmp, op);
|
||||
@@ -923,6 +949,11 @@ ZEND_API void ZEND_COLD zend_oob_string_to_long_error(const zend_string *s)
|
||||
zend_error_unchecked(E_WARNING, "The float-string \"%s\" is not representable as an int, cast occurred", ZSTR_VAL(s));
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_COLD zend_nan_coerced_to_type_warning(uint8_t type)
|
||||
{
|
||||
zend_error(E_WARNING, "unexpected NAN value was coerced to %s", zend_get_type_by_const(type));
|
||||
}
|
||||
|
||||
ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(const zval *op, bool is_strict) /* {{{ */
|
||||
{
|
||||
try_again:
|
||||
@@ -2254,6 +2285,8 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
|
||||
double str_dval;
|
||||
uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
|
||||
|
||||
ZEND_ASSERT(!zend_isnan(dval));
|
||||
|
||||
if (type == IS_LONG) {
|
||||
return ZEND_THREEWAY_COMPARE(dval, (double) str_lval);
|
||||
}
|
||||
@@ -2272,7 +2305,7 @@ static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
|
||||
|
||||
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
|
||||
{
|
||||
int converted = 0;
|
||||
bool converted = false;
|
||||
zval op1_copy, op2_copy;
|
||||
|
||||
while (1) {
|
||||
@@ -2379,7 +2412,27 @@ ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
|
||||
}
|
||||
|
||||
if (!converted) {
|
||||
if (Z_TYPE_P(op1) < IS_TRUE) {
|
||||
/* Handle NAN */
|
||||
if (UNEXPECTED(
|
||||
(Z_TYPE_P(op1) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op1)))
|
||||
|| (Z_TYPE_P(op2) == IS_DOUBLE && zend_isnan(Z_DVAL_P(op2)))
|
||||
)) {
|
||||
// TODO: NAN should always be uncomparable
|
||||
/* NAN used be cast to TRUE so handle this manually for the time being */
|
||||
if (Z_TYPE_P(op1) < IS_TRUE) {
|
||||
return -1;
|
||||
} else if (Z_TYPE_P(op1) == IS_TRUE || Z_TYPE_P(op2) == IS_TRUE) {
|
||||
return 0;
|
||||
} else if (Z_TYPE_P(op2) < IS_TRUE) {
|
||||
return 1;
|
||||
} else if (Z_TYPE_P(op1) != IS_DOUBLE) {
|
||||
op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
|
||||
converted = true;
|
||||
} else if (Z_TYPE_P(op2) != IS_DOUBLE) {
|
||||
op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
|
||||
converted = true;
|
||||
}
|
||||
} else if (Z_TYPE_P(op1) < IS_TRUE) {
|
||||
return zval_is_true(op2) ? -1 : 0;
|
||||
} else if (Z_TYPE_P(op1) == IS_TRUE) {
|
||||
return zval_is_true(op2) ? 0 : 1;
|
||||
@@ -2393,7 +2446,7 @@ ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
|
||||
if (EG(exception)) {
|
||||
return 1; /* to stop comparison of arrays */
|
||||
}
|
||||
converted = 1;
|
||||
converted = true;
|
||||
}
|
||||
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
|
||||
return 1;
|
||||
@@ -3551,6 +3604,9 @@ ZEND_API zend_string* ZEND_FASTCALL zend_double_to_str(double num)
|
||||
int precision = (int) EG(precision);
|
||||
zend_gcvt(num, precision ? precision : 1, '.', 'E', buf);
|
||||
zend_string *str = zend_string_init(buf, strlen(buf), 0);
|
||||
if (UNEXPECTED(zend_isnan(num))) {
|
||||
zend_nan_coerced_to_type_warning(IS_STRING);
|
||||
}
|
||||
GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ ZEND_API void zend_incompatible_double_to_long_error(double d);
|
||||
ZEND_API void zend_incompatible_string_to_long_error(const zend_string *s);
|
||||
ZEND_API void ZEND_COLD zend_oob_double_to_long_error(double d);
|
||||
ZEND_API void ZEND_COLD zend_oob_string_to_long_error(const zend_string *s);
|
||||
ZEND_API void ZEND_COLD zend_nan_coerced_to_type_warning(uint8_t type);
|
||||
|
||||
ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d);
|
||||
|
||||
@@ -421,6 +422,9 @@ again:
|
||||
}
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
if (UNEXPECTED(zend_isnan(Z_DVAL_P(op)))) {
|
||||
zend_nan_coerced_to_type_warning(_IS_BOOL);
|
||||
}
|
||||
if (Z_DVAL_P(op)) {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "Zend/zend_portability.h"
|
||||
#include "Zend/zend_types.h"
|
||||
#include "Zend/zend_API.h"
|
||||
|
||||
@@ -2653,6 +2654,11 @@ static void ZEND_FASTCALL zend_jit_invalid_array_access(zval *container)
|
||||
zend_error(E_WARNING, "Trying to access array offset on %s", zend_zval_value_name(container));
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_nan_coerced_to_type_warning(void)
|
||||
{
|
||||
zend_nan_coerced_to_type_warning(_IS_BOOL);
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_invalid_property_read(zval *container, const char *property_name)
|
||||
{
|
||||
zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", property_name, zend_zval_value_name(container));
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* +----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "Zend/zend_types.h"
|
||||
#include "Zend/zend_type_info.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/ir/ir_builder.h"
|
||||
@@ -7566,7 +7567,9 @@ static int zend_jit_bool_jmpznz(zend_jit_ctx *jit, const zend_op *opline, uint32
|
||||
op1_addr = ZEND_ADDR_REF_ZVAL(ref);
|
||||
}
|
||||
|
||||
if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
|
||||
if (Z_MODE(op1_addr) == IS_CONST_ZVAL
|
||||
/* NAN Value must cause a warning to be emitted */
|
||||
&& (Z_TYPE_P(Z_ZV(op1_addr)) != IS_DOUBLE || !zend_isnan(Z_DVAL_P(Z_ZV(op1_addr))))) {
|
||||
if (zend_is_true(Z_ZV(op1_addr))) {
|
||||
always_true = 1;
|
||||
} else {
|
||||
@@ -7734,7 +7737,15 @@ static int zend_jit_bool_jmpznz(zend_jit_ctx *jit, const zend_op *opline, uint32
|
||||
if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
|
||||
ir_IF_TRUE(if_double);
|
||||
}
|
||||
ref = ir_NE(jit_Z_DVAL(jit, op1_addr), ir_CONST_DOUBLE(0.0));
|
||||
|
||||
ir_ref dval = jit_Z_DVAL(jit, op1_addr);
|
||||
ir_ref is_nan = ir_NE(dval, dval);
|
||||
ir_ref if_val = ir_IF(is_nan);
|
||||
ir_IF_TRUE_cold(if_val);
|
||||
ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_nan_coerced_to_type_warning));
|
||||
ir_MERGE_WITH_EMPTY_FALSE(if_val);
|
||||
|
||||
ref = ir_NE(dval, ir_CONST_DOUBLE(0.0));
|
||||
if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
|
||||
if (set_bool_not) {
|
||||
jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
|
||||
|
||||
@@ -13,7 +13,12 @@ for ($i = 0; $i < 3; $i++) {
|
||||
else { echo "nan is false\n"; }
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
nan is true
|
||||
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
nan is true
|
||||
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
nan is true
|
||||
|
||||
@@ -33,9 +33,16 @@ test2(NAN, false);
|
||||
test2(1.0, false);
|
||||
test2(0.0, false);
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
string(1) "1"
|
||||
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
bool(true)
|
||||
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
bool(false)
|
||||
|
||||
string(1) "1"
|
||||
@@ -46,10 +53,14 @@ string(1) "2"
|
||||
bool(false)
|
||||
bool(true)
|
||||
|
||||
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
|
||||
|
||||
Warning: unexpected NAN value was coerced to bool in %s on line %d
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
|
||||
@@ -16,9 +16,16 @@ var_dump($f3);
|
||||
|
||||
$fs = [$f1, $f2, $f3, 5.5];
|
||||
|
||||
function safe_to_string(int|float $number): string {
|
||||
if (is_nan($number)) {
|
||||
return 'NAN';
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
foreach ($fs as $s) {
|
||||
foreach ($fs as $e) {
|
||||
echo "range($s, $e);\n";
|
||||
echo 'range(', safe_to_string($s), ', ', safe_to_string($e), ");\n";
|
||||
try {
|
||||
var_dump( range($s, $e) );
|
||||
} catch (\ValueError $e) {
|
||||
|
||||
@@ -9,7 +9,7 @@ var_dump(gettype(get_defined_constants()));
|
||||
|
||||
$arr1 = get_defined_constants(false);
|
||||
$arr2 = get_defined_constants();
|
||||
var_dump(array_diff($arr1, $arr2));
|
||||
var_dump(array_diff_key($arr1, $arr2));
|
||||
|
||||
$n1 = count(get_defined_constants());
|
||||
define("USER_CONSTANT", "test");
|
||||
|
||||
@@ -24,13 +24,20 @@ $numbers = [
|
||||
NAN,
|
||||
];
|
||||
|
||||
function safe_to_string(int|float $number): string {
|
||||
if (is_nan($number)) {
|
||||
return 'NAN';
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
foreach ($numbers as $base) {
|
||||
foreach ($numbers as $exp) {
|
||||
print str_pad($base, 4, " ", STR_PAD_LEFT) .
|
||||
" ** " .
|
||||
str_pad($exp, 4) .
|
||||
" = " .
|
||||
fpow($base, $exp) .
|
||||
echo str_pad(safe_to_string($base), 4, " ", STR_PAD_LEFT),
|
||||
" ** ",
|
||||
str_pad(safe_to_string($exp), 4),
|
||||
" = ",
|
||||
safe_to_string(fpow($base, $exp)),
|
||||
PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,40 +8,51 @@ if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$bases = array(23,
|
||||
-23,
|
||||
23.1,
|
||||
-23.1,
|
||||
2.345e1,
|
||||
-2.345e1,
|
||||
0x17,
|
||||
027,
|
||||
"23",
|
||||
"23.45",
|
||||
"2.345e1",
|
||||
PHP_INT_MAX,
|
||||
-PHP_INT_MAX - 1);
|
||||
$bases = [
|
||||
23,
|
||||
-23,
|
||||
23.1,
|
||||
-23.1,
|
||||
2.345e1,
|
||||
-2.345e1,
|
||||
0x17,
|
||||
027,
|
||||
"23",
|
||||
"23.45",
|
||||
"2.345e1",
|
||||
PHP_INT_MAX,
|
||||
-PHP_INT_MAX - 1,
|
||||
];
|
||||
|
||||
$exponents = array(0,
|
||||
1,
|
||||
-1,
|
||||
2,
|
||||
-2,
|
||||
3,
|
||||
-3,
|
||||
2.5,
|
||||
-2.5,
|
||||
500,
|
||||
-500,
|
||||
2147483647,
|
||||
-2147483648);
|
||||
$exponents = [
|
||||
0,
|
||||
1,
|
||||
-1,
|
||||
2,
|
||||
-2,
|
||||
3,
|
||||
-3,
|
||||
2.5,
|
||||
-2.5,
|
||||
500,
|
||||
-500,
|
||||
2147483647,
|
||||
-2147483648
|
||||
];
|
||||
|
||||
function safe_to_string(int|float $number): string {
|
||||
if (is_nan($number)) {
|
||||
return 'NAN';
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
foreach($bases as $base) {
|
||||
echo "\n\nBase = $base";
|
||||
foreach($exponents as $exponent) {
|
||||
echo "\n..... Exponent = $exponent Result = ";
|
||||
$res = pow($base, $exponent);
|
||||
echo $res;
|
||||
echo safe_to_string($res);
|
||||
}
|
||||
echo "\n\n";
|
||||
}
|
||||
|
||||
@@ -8,40 +8,51 @@ if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$bases = array(23,
|
||||
-23,
|
||||
23.1,
|
||||
-23.1,
|
||||
2.345e1,
|
||||
-2.345e1,
|
||||
0x17,
|
||||
027,
|
||||
"23",
|
||||
"23.45",
|
||||
"2.345e1",
|
||||
PHP_INT_MAX,
|
||||
-PHP_INT_MAX - 1);
|
||||
$bases = [
|
||||
23,
|
||||
-23,
|
||||
23.1,
|
||||
-23.1,
|
||||
2.345e1,
|
||||
-2.345e1,
|
||||
0x17,
|
||||
027,
|
||||
"23",
|
||||
"23.45",
|
||||
"2.345e1",
|
||||
PHP_INT_MAX,
|
||||
-PHP_INT_MAX - 1,
|
||||
];
|
||||
|
||||
$exponents = array(0,
|
||||
1,
|
||||
-1,
|
||||
2,
|
||||
-2,
|
||||
3,
|
||||
-3,
|
||||
2.5,
|
||||
-2.5,
|
||||
500,
|
||||
-500,
|
||||
2147483647,
|
||||
-2147483648);
|
||||
$exponents = [
|
||||
0,
|
||||
1,
|
||||
-1,
|
||||
2,
|
||||
-2,
|
||||
3,
|
||||
-3,
|
||||
2.5,
|
||||
-2.5,
|
||||
500,
|
||||
-500,
|
||||
2147483647,
|
||||
-2147483648
|
||||
];
|
||||
|
||||
function safe_to_string(int|float $number): string {
|
||||
if (is_nan($number)) {
|
||||
return 'NAN';
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
foreach($bases as $base) {
|
||||
echo "\n\nBase = $base";
|
||||
foreach($exponents as $exponent) {
|
||||
echo "\n..... Exponent = $exponent Result = ";
|
||||
$res = pow($base, $exponent);
|
||||
echo $res;
|
||||
echo safe_to_string($res);
|
||||
}
|
||||
echo "\n\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user