diff options
25 files changed, 134 insertions, 42 deletions
@@ -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. ======================================== diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index c5a41f2198..7b03440a53 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -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 ======================== diff --git a/Zend/tests/add_002.phpt b/Zend/tests/add_002.phpt index 4d804fe3e8..1e9148ffa5 100644 --- a/Zend/tests/add_002.phpt +++ b/Zend/tests/add_002.phpt @@ -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: diff --git a/Zend/tests/add_003.phpt b/Zend/tests/add_003.phpt index a3705479e2..cc2a0dd1a7 100644 --- a/Zend/tests/add_003.phpt +++ b/Zend/tests/add_003.phpt @@ -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: diff --git a/Zend/tests/assert/indirect_var_access_misoptimization.phpt b/Zend/tests/assert/indirect_var_access_misoptimization.phpt index 6c05a8c607..02327f30c0 100644 --- a/Zend/tests/assert/indirect_var_access_misoptimization.phpt +++ b/Zend/tests/assert/indirect_var_access_misoptimization.phpt @@ -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) diff --git a/Zend/tests/bug73337.phpt b/Zend/tests/bug73337.phpt index 9eff18e643..53ce963c52 100644 --- a/Zend/tests/bug73337.phpt +++ b/Zend/tests/bug73337.phpt @@ -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 diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 357368f88d..7e19683094 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -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"; } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 98ae806adb..33db03636c 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -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; diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 1b155f88f7..daed16e358 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -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)) { \ diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 0ccc92425c..a0abe5acb7 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -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; diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index d28398315d..e6d62c3640 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -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: diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 85a2258e19..5783e0d02f 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -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; } diff --git a/ext/intl/tests/bug48227.phpt b/ext/intl/tests/bug48227.phpt index 0ac0d5e555..42a4ffaf86 100644 --- a/ext/intl/tests/bug48227.phpt +++ b/ext/intl/tests/bug48227.phpt @@ -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" diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 66ac14ad88..715b31f420 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -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; } diff --git a/ext/simplexml/tests/bug53033.phpt b/ext/simplexml/tests/bug53033.phpt new file mode 100644 index 0000000000..626022cd54 --- /dev/null +++ b/ext/simplexml/tests/bug53033.phpt @@ -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) diff --git a/ext/simplexml/tests/bug54973.phpt b/ext/simplexml/tests/bug54973.phpt new file mode 100644 index 0000000000..29daaed788 --- /dev/null +++ b/ext/simplexml/tests/bug54973.phpt @@ -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) diff --git a/ext/standard/tests/math/abs_variation.phpt b/ext/standard/tests/math/abs_variation.phpt index 6df1e6b55c..ed9085446b 100644 --- a/ext/standard/tests/math/abs_variation.phpt +++ b/ext/standard/tests/math/abs_variation.phpt @@ -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===
\ No newline at end of file +===Done=== diff --git a/ext/standard/tests/math/ceil_variation1.phpt b/ext/standard/tests/math/ceil_variation1.phpt index 7c1f859277..35a9e1d4a3 100644 --- a/ext/standard/tests/math/ceil_variation1.phpt +++ b/ext/standard/tests/math/ceil_variation1.phpt @@ -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 -- diff --git a/ext/standard/tests/math/floor_variation1.phpt b/ext/standard/tests/math/floor_variation1.phpt index baba53aab4..fcb895164a 100644 --- a/ext/standard/tests/math/floor_variation1.phpt +++ b/ext/standard/tests/math/floor_variation1.phpt @@ -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 -- diff --git a/ext/standard/tests/math/pow_variation1.phpt b/ext/standard/tests/math/pow_variation1.phpt index c744c4eb9d..3b1befe16b 100644 --- a/ext/standard/tests/math/pow_variation1.phpt +++ b/ext/standard/tests/math/pow_variation1.phpt @@ -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 -- diff --git a/ext/standard/tests/math/pow_variation1_64bit.phpt b/ext/standard/tests/math/pow_variation1_64bit.phpt index ea2ae45d18..35f9942490 100644 --- a/ext/standard/tests/math/pow_variation1_64bit.phpt +++ b/ext/standard/tests/math/pow_variation1_64bit.phpt @@ -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 -- diff --git a/ext/standard/tests/math/pow_variation2.phpt b/ext/standard/tests/math/pow_variation2.phpt index 36b085b647..d93a952dbe 100644 --- a/ext/standard/tests/math/pow_variation2.phpt +++ b/ext/standard/tests/math/pow_variation2.phpt @@ -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 -- diff --git a/ext/standard/tests/math/round_variation1.phpt b/ext/standard/tests/math/round_variation1.phpt index c89dd6818a..c1883a5c1b 100644 --- a/ext/standard/tests/math/round_variation1.phpt +++ b/ext/standard/tests/math/round_variation1.phpt @@ -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 -- diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index 63f8c968c3..355e4f0f1e 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -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; |