]> granicus.if.org Git - php/commitdiff
Add _IS_NUMBER as cast_object() target type
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 25 Dec 2017 12:18:45 +0000 (13:18 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 26 Dec 2017 11:39:06 +0000 (12:39 +0100)
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.

25 files changed:
NEWS
UPGRADING
UPGRADING.INTERNALS
Zend/tests/add_002.phpt
Zend/tests/add_003.phpt
Zend/tests/assert/indirect_var_access_misoptimization.phpt
Zend/tests/bug73337.phpt
Zend/zend_API.c
Zend/zend_object_handlers.c
Zend/zend_operators.c
Zend/zend_types.h
ext/com_dotnet/com_handlers.c
ext/gmp/gmp.c
ext/intl/tests/bug48227.phpt
ext/simplexml/simplexml.c
ext/simplexml/tests/bug53033.phpt [new file with mode: 0644]
ext/simplexml/tests/bug54973.phpt [new file with mode: 0644]
ext/standard/tests/math/abs_variation.phpt
ext/standard/tests/math/ceil_variation1.phpt
ext/standard/tests/math/floor_variation1.phpt
ext/standard/tests/math/pow_variation1.phpt
ext/standard/tests/math/pow_variation1_64bit.phpt
ext/standard/tests/math/pow_variation2.phpt
ext/standard/tests/math/round_variation1.phpt
ext/tidy/tidy.c

diff --git a/NEWS b/NEWS
index 3757f65384b7e2da7f9cb175cd3c6a9cce70b70b..e8fc786555db3f0f94edf50dd9e0bad43d433dd7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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)
 
index 85d74a02c5fb88e572315254d8067eae84248101..3565c28a965915bff0c88629f59bbf3a6947aa9c 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -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.
 
 ========================================
index c5a41f2198833d9ef060946495a244b40b40e582..7b03440a53b6aa5a5fc1aeaf831e0654739146ed 100644 (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
 ========================
index 4d804fe3e8df759499dc70d7573966f02a149d41..1e9148ffa59cfbe8efdc26b152bfb00a44e9b8d0 100644 (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:
index a3705479e254c6c931e7200f211b6186dd03edc8..cc2a0dd1a7e4b64b5630807c2f813caf8f21e679 100644 (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:
index 6c05a8c607e04167acceaa84e1919cee2e0dbb5c..02327f30c026690b832f6dcc3010a847e8bc86e8 100644 (file)
@@ -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)
index 9eff18e6433914d2e1034e258f9a68996ffb74d5..53ce963c529fa981124b98436c54fdd08b4ca52d 100644 (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
index 357368f88d3da3b3168a7d919ad4aaeec27103ad..7e19683094f584813e9cc1071179727a328d4556 100644 (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";
        }
index 98ae806adbeb9529ad4c789ddfe3410cdc6e18fd..33db03636c5847b93437beb02d461d6c46e8988e 100644 (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;
index 1b155f88f7965bfb892b897603bec802257c14ae..daed16e35890aa82d7dab4ed7ccd8c5a8c902972 100644 (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)) {                                             \
index 0ccc92425caaf265cdc81d2fa8efb6e0284db89c..a0abe5acb76b65fbcdf3125fc059f41b57f85da5 100644 (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;
index d28398315d893f8f33d0458f77330aef50c60f30..e6d62c36400303922c01897832460929bd9337ee 100644 (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:
index 85a2258e1952f8b626037b7b47992c3d330e6bf5..5783e0d02f2fd33025e6b7338f4aa6900116a90b 100644 (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;
        }
index 0ac0d5e55541fb6d02b84019f91ee7cd568a3ae4..42a4ffaf867a208a3cd9e24535e8c4ad7e78da74 100644 (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"
index 66ac14ad8845a2e7ed6533bf3ea0da7d6d1a7a9d..715b31f420dda66700ced6e3589bd48ae2530ed0 100644 (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;
        }
diff --git a/ext/simplexml/tests/bug53033.phpt b/ext/simplexml/tests/bug53033.phpt
new file mode 100644 (file)
index 0000000..626022c
--- /dev/null
@@ -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 (file)
index 0000000..29daaed
--- /dev/null
@@ -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)
index 6df1e6b55cec11f0a5699d11c276c16c66745cc5..ed9085446bf6f69a0348f627d031823cba196798 100644 (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===
\ No newline at end of file
+===Done===
index 7c1f8592772ee625f9e74024f53fa66b0c700040..35a9e1d4a33267ffd2af2185bf703fcbbb1ab276 100644 (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 --
index baba53aab4c6f2422607e7b6195e66c87724c7a9..fcb895164a7248003da2f8c2616c36aafa461f31 100644 (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 --
index c744c4eb9d48f9293edc66dba5da420e6cec92e3..3b1befe16be2c84501a0035b43637735c05b3136 100644 (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 --
index ea2ae45d18a6add99a868f09ebf1810286168ebf..35f9942490bc2ada5e3bb90e6bc14de70f14cccb 100644 (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 --
index 36b085b647434788e9428418c6a9ef41533942e9..d93a952dbe28e54135d1735629a5e0c2bbdc91d5 100644 (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 --
index c89dd6818a37ac9f16badf9574111b75fd91b47a..c1883a5c1bc309c368a0b0b3855d76abd0a04dbb 100644 (file)
@@ -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 --
index 63f8c968c3e6f38373833c5754704f291d1c87b1..355e4f0f1eac6b80cc68883f8653577ac6b423ef 100644 (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;