1
0
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:
Nikita Popov
2017-12-25 13:18:45 +01:00
parent efcbea4345
commit b2b2b437af
25 changed files with 134 additions and 42 deletions
+7
View File
@@ -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)
+7 -2
View File
@@ -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.
========================================
+5
View File
@@ -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
========================
+2 -2
View File
@@ -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:
+2 -2
View File
@@ -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)
+2 -2
View File
@@ -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
+2
View File
@@ -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";
}
+5
View File
@@ -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
View File
@@ -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)) { \
+1
View File
@@ -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;
+1
View File
@@ -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:
+8
View File
@@ -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;
}
+1 -1
View File
@@ -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"
+3
View File
@@ -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;
}
+21
View File
@@ -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)
+21
View File
@@ -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)
+2 -2
View File
@@ -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===
+1 -1
View File
@@ -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 --
+1 -1
View File
@@ -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 --
+1 -1
View File
@@ -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 --
+2
View File
@@ -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;