mirror of
https://github.com/php/php-src.git
synced 2026-04-27 10:16:41 +02:00
Add _IS_NUMBER as cast_object() target type
convert_scalar_to_number() will now call cast_object() with an _IS_NUMBER argument, in which case the cast handler should return either an integer or floating point number, whichever is more appropriate. Previously convert_scalar_to_number() unconditionally converted objects to integers instead. Fixes bug #53033. Fixes bug #54973. Fixes bug #73108.
This commit is contained in:
@@ -27,6 +27,10 @@ PHP NEWS
|
||||
function). (Li-Wen Hsu)
|
||||
. Fixed bug #54043 (Remove inconsitency of internal exceptions and user
|
||||
defined exceptions). (Nikita)
|
||||
. Fixed bug #53033 (Mathematical operations convert objects to integers).
|
||||
(Nikita)
|
||||
. Fixed bug #73108 (Internal class cast handler uses integer instead of
|
||||
float). (Nikita)
|
||||
|
||||
- BCMath:
|
||||
. Fixed bug #66364 (BCMath bcmul ignores scale parameter). (cmb)
|
||||
@@ -132,6 +136,9 @@ PHP NEWS
|
||||
. Fixed bug #74941 (session fails to start after having headers sent).
|
||||
(morozov)
|
||||
|
||||
- SimpleXML:
|
||||
. Fixed bug #54973 (SimpleXML casts integers wrong). (Nikita)
|
||||
|
||||
- SOAP:
|
||||
. Fixed bug #75464 (Wrong reflection on SoapClient::__setSoapHeaders). (villfa)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Core:
|
||||
|
||||
BCMath:
|
||||
. All warnings thrown by BCMath functions are now using PHP's error handling.
|
||||
Formerly some warnings have directly been written to stderr.
|
||||
Formerly some warnings have directly been written to stderr.
|
||||
. bcmul() and bcpow() now return numbers with the requested scale. Formerly,
|
||||
the returned numbers may have omitted trailing decimal zeroes.
|
||||
|
||||
@@ -40,6 +40,11 @@ SPL:
|
||||
executed. Previously all autoloaders were executed and exceptions were
|
||||
chained.
|
||||
|
||||
SimpleXML:
|
||||
. Mathematic operations involving SimpleXML objects will now treat the text as
|
||||
an integer or float, whichever is more appropriate. Previously values were
|
||||
treated as integers unconditionally.
|
||||
|
||||
Standard:
|
||||
. getimagesize() and related functions now report the mime type of BMP images
|
||||
as image/bmp instead of image/x-ms-bmp, since the former has been registered
|
||||
@@ -140,7 +145,7 @@ JSON:
|
||||
. Support for Birdstep has been removed.
|
||||
|
||||
ZIP:
|
||||
. Bunled libzip has been dropped,
|
||||
. Bundled libzip has been dropped,
|
||||
system library is now required.
|
||||
|
||||
========================================
|
||||
|
||||
@@ -10,6 +10,7 @@ PHP 7.3 INTERNALS UPGRADE NOTES
|
||||
g. zend_get_parameters()
|
||||
h. zend_register_persistent_resource()
|
||||
i. RAND_RANGE()
|
||||
j. cast_object() with _IS_NUMBER
|
||||
|
||||
2. Build system changes
|
||||
a. Unix build system changes
|
||||
@@ -86,6 +87,10 @@ PHP 7.3 INTERNALS UPGRADE NOTES
|
||||
i. The RANGE_RANGE() macro has been removed. php_mt_rand_range() should be
|
||||
used instead.
|
||||
|
||||
j. The cast_object() object handler now also accepts the _IS_NUMBER type. The
|
||||
handler should return either an integer or float value in this case,
|
||||
whichever is more appropriate.
|
||||
|
||||
========================
|
||||
2. Build system changes
|
||||
========================
|
||||
|
||||
@@ -20,11 +20,11 @@ var_dump($c);
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Notice: Object of class stdClass could not be converted to int in %sadd_002.php on line %d
|
||||
Notice: Object of class stdClass could not be converted to number in %sadd_002.php on line %d
|
||||
|
||||
Exception: Unsupported operand types
|
||||
|
||||
Notice: Object of class stdClass could not be converted to int in %s on line %d
|
||||
Notice: Object of class stdClass could not be converted to number in %s on line %d
|
||||
|
||||
Fatal error: Uncaught Error: Unsupported operand types in %s:%d
|
||||
Stack trace:
|
||||
|
||||
@@ -20,11 +20,11 @@ var_dump($c);
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Notice: Object of class stdClass could not be converted to int in %sadd_003.php on line %d
|
||||
Notice: Object of class stdClass could not be converted to number in %sadd_003.php on line %d
|
||||
|
||||
Exception: Unsupported operand types
|
||||
|
||||
Notice: Object of class stdClass could not be converted to int in %s on line %d
|
||||
Notice: Object of class stdClass could not be converted to number in %s on line %d
|
||||
|
||||
Fatal error: Uncaught Error: Unsupported operand types in %s:%d
|
||||
Stack trace:
|
||||
|
||||
@@ -17,5 +17,5 @@ test();
|
||||
--EXPECTF--
|
||||
Deprecated: assert(): Calling assert() with a string argument is deprecated in %s on line %d
|
||||
|
||||
Notice: Object of class stdClass could not be converted to int in %s on line %d
|
||||
Notice: Object of class stdClass could not be converted to number in %s on line %d
|
||||
int(2)
|
||||
|
||||
@@ -6,7 +6,7 @@ class d { function __destruct() { throw new Exception; } }
|
||||
try { new d + new d; } catch (Exception $e) { print "Exception properly caught\n"; }
|
||||
?>
|
||||
--EXPECTF--
|
||||
Notice: Object of class d could not be converted to int in %sbug73337.php on line 3
|
||||
Notice: Object of class d could not be converted to number in %sbug73337.php on line 3
|
||||
|
||||
Notice: Object of class d could not be converted to int in %sbug73337.php on line 3
|
||||
Notice: Object of class d could not be converted to number in %sbug73337.php on line 3
|
||||
Exception properly caught
|
||||
|
||||
@@ -126,6 +126,8 @@ ZEND_API char *zend_get_type_by_const(int type) /* {{{ */
|
||||
return "array";
|
||||
case IS_VOID:
|
||||
return "void";
|
||||
case _IS_NUMBER:
|
||||
return "number";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
@@ -1698,6 +1698,11 @@ ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int ty
|
||||
zend_error(E_NOTICE, "Object of class %s could not be converted to float", ZSTR_VAL(ce->name));
|
||||
ZVAL_DOUBLE(writeobj, 1);
|
||||
return SUCCESS;
|
||||
case _IS_NUMBER:
|
||||
ce = Z_OBJCE_P(readobj);
|
||||
zend_error(E_NOTICE, "Object of class %s could not be converted to number", ZSTR_VAL(ce->name));
|
||||
ZVAL_LONG(writeobj, 1);
|
||||
return SUCCESS;
|
||||
default:
|
||||
ZVAL_NULL(writeobj);
|
||||
break;
|
||||
|
||||
+35
-24
@@ -136,6 +136,26 @@ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* {
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
|
||||
#define convert_object_to_type(op, dst, ctype, conv_func) \
|
||||
ZVAL_UNDEF(dst); \
|
||||
if (Z_OBJ_HT_P(op)->cast_object) { \
|
||||
if (Z_OBJ_HT_P(op)->cast_object(op, dst, ctype) == FAILURE) { \
|
||||
zend_error(E_RECOVERABLE_ERROR, \
|
||||
"Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
|
||||
zend_get_type_by_const(ctype)); \
|
||||
} \
|
||||
} else if (Z_OBJ_HT_P(op)->get) { \
|
||||
zval *newop = Z_OBJ_HT_P(op)->get(op, dst); \
|
||||
if (Z_TYPE_P(newop) != IS_OBJECT) { \
|
||||
/* for safety - avoid loop */ \
|
||||
ZVAL_COPY_VALUE(dst, newop); \
|
||||
conv_func(dst); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
void ZEND_FASTCALL _convert_scalar_to_number(zval *op, zend_bool silent) /* {{{ */
|
||||
{
|
||||
try_again:
|
||||
@@ -172,7 +192,18 @@ try_again:
|
||||
}
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
convert_to_long_base(op, 10);
|
||||
{
|
||||
zval dst;
|
||||
|
||||
convert_object_to_type(op, &dst, _IS_NUMBER, convert_scalar_to_number);
|
||||
zval_dtor(op);
|
||||
|
||||
if (Z_TYPE(dst) == IS_LONG || Z_TYPE(dst) == IS_DOUBLE) {
|
||||
ZVAL_COPY_VALUE(op, &dst);
|
||||
} else {
|
||||
ZVAL_LONG(op, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -215,17 +246,17 @@ ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
|
||||
break; \
|
||||
case IS_OBJECT: \
|
||||
ZVAL_COPY(&(holder), op); \
|
||||
convert_to_long_base(&(holder), 10); \
|
||||
_convert_scalar_to_number(&(holder), silent); \
|
||||
if (UNEXPECTED(EG(exception))) { \
|
||||
if (result != op1) { \
|
||||
ZVAL_UNDEF(result); \
|
||||
} \
|
||||
return FAILURE; \
|
||||
} \
|
||||
if (Z_TYPE(holder) == IS_LONG) { \
|
||||
if (Z_TYPE(holder) == IS_LONG || Z_TYPE(holder) == IS_DOUBLE) { \
|
||||
if (op == result) { \
|
||||
zval_ptr_dtor(op); \
|
||||
ZVAL_LONG(op, Z_LVAL(holder)); \
|
||||
ZVAL_COPY(op, &(holder)); \
|
||||
} else { \
|
||||
(op) = &(holder); \
|
||||
} \
|
||||
@@ -237,26 +268,6 @@ ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
|
||||
#define convert_object_to_type(op, dst, ctype, conv_func) \
|
||||
ZVAL_UNDEF(dst); \
|
||||
if (Z_OBJ_HT_P(op)->cast_object) { \
|
||||
if (Z_OBJ_HT_P(op)->cast_object(op, dst, ctype) == FAILURE) { \
|
||||
zend_error(E_RECOVERABLE_ERROR, \
|
||||
"Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
|
||||
zend_get_type_by_const(ctype)); \
|
||||
} \
|
||||
} else if (Z_OBJ_HT_P(op)->get) { \
|
||||
zval *newop = Z_OBJ_HT_P(op)->get(op, dst); \
|
||||
if (Z_TYPE_P(newop) != IS_OBJECT) { \
|
||||
/* for safety - avoid loop */ \
|
||||
ZVAL_COPY_VALUE(dst, newop); \
|
||||
conv_func(dst); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, op, op_func) \
|
||||
do { \
|
||||
if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { \
|
||||
|
||||
@@ -386,6 +386,7 @@ struct _zend_ast_ref {
|
||||
#define IS_CALLABLE 17
|
||||
#define IS_ITERABLE 18
|
||||
#define IS_VOID 19
|
||||
#define _IS_NUMBER 20
|
||||
|
||||
static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
|
||||
return pz->u1.v.type;
|
||||
|
||||
@@ -484,6 +484,7 @@ static int com_object_cast(zval *readobj, zval *writeobj, int type)
|
||||
|
||||
switch(type) {
|
||||
case IS_LONG:
|
||||
case _IS_NUMBER:
|
||||
vt = VT_INT;
|
||||
break;
|
||||
case IS_DOUBLE:
|
||||
|
||||
@@ -425,6 +425,14 @@ static int gmp_cast_object(zval *readobj, zval *writeobj, int type) /* {{{ */
|
||||
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
||||
ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
|
||||
return SUCCESS;
|
||||
case _IS_NUMBER:
|
||||
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
||||
if (mpz_fits_slong_p(gmpnum)) {
|
||||
ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
|
||||
} else {
|
||||
ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
|
||||
}
|
||||
return SUCCESS;
|
||||
default:
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
@@ -17,5 +17,5 @@ string(1) "0"
|
||||
string(1) "1"
|
||||
string(1) "0"
|
||||
|
||||
Notice: Object of class NumberFormatter could not be converted to int in %s on line %d
|
||||
Notice: Object of class NumberFormatter could not be converted to number in %s on line %d
|
||||
string(1) "1"
|
||||
|
||||
@@ -1857,6 +1857,9 @@ static int cast_object(zval *object, int type, char *contents)
|
||||
case IS_DOUBLE:
|
||||
convert_to_double(object);
|
||||
break;
|
||||
case _IS_NUMBER:
|
||||
convert_scalar_to_number(object);
|
||||
break;
|
||||
default:
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Bug #53033: Mathematical operations convert objects to integers
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$x = simplexml_load_string('<x>2.5</x>');
|
||||
var_dump($x*1);
|
||||
// type of other operand is irrelevant
|
||||
var_dump($x*1.0);
|
||||
|
||||
// strings behave differently
|
||||
$y = '2.5';
|
||||
var_dump($y*1);
|
||||
var_dump((string)$x*1);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
float(2.5)
|
||||
float(2.5)
|
||||
float(2.5)
|
||||
float(2.5)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Bug #54973: SimpleXML casts integers wrong
|
||||
--FILE--
|
||||
<?php
|
||||
$xml = simplexml_load_string("<xml><number>9223372036854775808</number></xml>");
|
||||
|
||||
var_dump($xml->number);
|
||||
|
||||
$int = $xml->number / 1024 / 1024 / 1024;
|
||||
var_dump($int);
|
||||
|
||||
$double = (double) $xml->number / 1024 / 1024 / 1024;
|
||||
var_dump($double);
|
||||
?>
|
||||
--EXPECT--
|
||||
object(SimpleXMLElement)#2 (1) {
|
||||
[0]=>
|
||||
string(19) "9223372036854775808"
|
||||
}
|
||||
float(8589934592)
|
||||
float(8589934592)
|
||||
@@ -121,7 +121,7 @@ int(0)
|
||||
|
||||
-- Iteration 13 --
|
||||
|
||||
Notice: Object of class classA could not be converted to int in %s on line %d
|
||||
Notice: Object of class classA could not be converted to number in %s on line %d
|
||||
int(1)
|
||||
|
||||
-- Iteration 14 --
|
||||
@@ -132,4 +132,4 @@ int(0)
|
||||
|
||||
-- Iteration 16 --
|
||||
int(%d)
|
||||
===Done===
|
||||
===Done===
|
||||
|
||||
@@ -114,7 +114,7 @@ float(0)
|
||||
|
||||
-- Iteration 13 --
|
||||
|
||||
Notice: Object of class classA could not be converted to int in %s on line %d
|
||||
Notice: Object of class classA could not be converted to number in %s on line %d
|
||||
float(1)
|
||||
|
||||
-- Iteration 14 --
|
||||
|
||||
@@ -114,7 +114,7 @@ float(0)
|
||||
|
||||
-- Iteration 13 --
|
||||
|
||||
Notice: Object of class classA could not be converted to int in %s on line %d
|
||||
Notice: Object of class classA could not be converted to number in %s on line %d
|
||||
float(1)
|
||||
|
||||
-- Iteration 14 --
|
||||
|
||||
@@ -172,7 +172,7 @@ int(0)
|
||||
|
||||
-- Iteration 23 --
|
||||
|
||||
Notice: Object of class classA could not be converted to int in %s on line %d
|
||||
Notice: Object of class classA could not be converted to number in %s on line %d
|
||||
int(1)
|
||||
|
||||
-- Iteration 24 --
|
||||
|
||||
@@ -172,7 +172,7 @@ int(0)
|
||||
|
||||
-- Iteration 23 --
|
||||
|
||||
Notice: Object of class classA could not be converted to int in %s on line %d
|
||||
Notice: Object of class classA could not be converted to number in %s on line %d
|
||||
int(1)
|
||||
|
||||
-- Iteration 24 --
|
||||
|
||||
@@ -168,7 +168,7 @@ float(1)
|
||||
|
||||
-- Iteration 23 --
|
||||
|
||||
Notice: Object of class classA could not be converted to int in %s on line %d
|
||||
Notice: Object of class classA could not be converted to number in %s on line %d
|
||||
float(20.3)
|
||||
|
||||
-- Iteration 24 --
|
||||
|
||||
@@ -159,7 +159,7 @@ float(0)
|
||||
|
||||
-- Iteration 23 --
|
||||
|
||||
Notice: Object of class classA could not be converted to int in %s on line %d
|
||||
Notice: Object of class classA could not be converted to number in %s on line %d
|
||||
float(1)
|
||||
|
||||
-- Iteration 24 --
|
||||
|
||||
@@ -733,6 +733,7 @@ static int tidy_doc_cast_handler(zval *in, zval *out, int type)
|
||||
|
||||
switch (type) {
|
||||
case IS_LONG:
|
||||
case _IS_NUMBER:
|
||||
ZVAL_LONG(out, 0);
|
||||
break;
|
||||
|
||||
@@ -766,6 +767,7 @@ static int tidy_node_cast_handler(zval *in, zval *out, int type)
|
||||
|
||||
switch(type) {
|
||||
case IS_LONG:
|
||||
case _IS_NUMBER:
|
||||
ZVAL_LONG(out, 0);
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user