]> granicus.if.org Git - php/commitdiff
Make Exception::$trace typed array property
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 28 May 2020 10:23:37 +0000 (12:23 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 28 May 2020 11:55:38 +0000 (13:55 +0200)
This is a private property, so we are allowed to add a type.
The new declaration of the property is:

    private array $trace = [];

This ensures that Exception::getTrace() does indeed return an array.

Userland code that was modifying the property through refleciton
may have to be adjusted to assign an array (instead of null,
for example).

Closes GH-5636.

Zend/zend_API.c
Zend/zend_exceptions.c
ext/standard/tests/serialize/bug69152.phpt
ext/standard/tests/serialize/bug70963.phpt
sapi/cli/tests/005.phpt

index ba5cb9c747a05b3abc2314240bf43bd1cc13e16d..241cba8151ba4adb3eb8f6a0e8fa2dd00ec916e7 100644 (file)
@@ -3586,20 +3586,14 @@ ZEND_API int zend_declare_typed_property(zend_class_entry *ce, zend_string *name
                Z_PROP_FLAG_P(property_default_ptr) = Z_ISUNDEF_P(property) ? IS_PROP_UNINIT : 0;
        }
        if (ce->type & ZEND_INTERNAL_CLASS) {
-               switch(Z_TYPE_P(property)) {
-                       case IS_ARRAY:
-                       case IS_OBJECT:
-                       case IS_RESOURCE:
-                               zend_error_noreturn(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
-                               break;
-                       default:
-                               break;
-               }
-
                /* Must be interned to avoid ZTS data races */
                if (is_persistent_class(ce)) {
                        name = zend_new_interned_string(zend_string_copy(name));
                }
+
+               if (Z_REFCOUNTED_P(property)) {
+                       zend_error_noreturn(E_CORE_ERROR, "Internal zvals cannot be refcounted");
+               }
        }
 
        if (access_type & ZEND_ACC_PUBLIC) {
index 06c1c9897c25287736321c2911cbf93223e844a6..21775a26ca23135878619e2097d8ea9b11b7d68c 100644 (file)
@@ -606,10 +606,12 @@ ZEND_METHOD(Exception, getTraceAsString)
        base_ce = i_get_exception_base(object);
 
        trace = zend_read_property_ex(base_ce, object, ZSTR_KNOWN(ZEND_STR_TRACE), 1, &rv);
-       if (Z_TYPE_P(trace) != IS_ARRAY) {
-               zend_type_error("Trace is not an array");
-               return;
+       if (EG(exception)) {
+               RETURN_THROWS();
        }
+
+       /* Type should be guaranteed by property type. */
+       ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
        ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(trace), index, frame) {
                if (Z_TYPE_P(frame) != IS_ARRAY) {
                        zend_error(E_WARNING, "Expected array for frame " ZEND_ULONG_FMT, index);
@@ -736,12 +738,19 @@ ZEND_METHOD(Exception, __toString)
 
 static void declare_exception_properties(zend_class_entry *ce)
 {
+       zval val;
+
        zend_declare_property_string(ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED);
        zend_declare_property_string(ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE);
        zend_declare_property_long(ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED);
        zend_declare_property_null(ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED);
        zend_declare_property_null(ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED);
-       zend_declare_property_null(ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE);
+
+       ZVAL_EMPTY_ARRAY(&val);
+       zend_declare_typed_property(
+               ce, ZSTR_KNOWN(ZEND_STR_TRACE), &val, ZEND_ACC_PRIVATE, NULL,
+               (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY));
+
        zend_declare_property_null(ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE);
 }
 
index b11591ffc21850ac5a03035845f6bbe0238d21d4..f7f3b9ac8d33cfb1644566319c9701c76ecbdc0c 100644 (file)
@@ -9,6 +9,8 @@ $x->test();
 
 ?>
 --EXPECTF--
-Fatal error: Uncaught TypeError: Trace is not an array in %s:%d
-%a
+Fatal error: Uncaught TypeError: Cannot assign string to property Exception::$trace of type array in %s:%d
+Stack trace:
+#0 %s(%d): unserialize('O:9:"exception"...')
+#1 {main}
   thrown in %s on line %d
index c4e2267b043d54a74d9d537b995bfa01b33c4b37..63f5845ae0d8c45eaa9c2dee5da52fabe665a87a 100644 (file)
@@ -6,25 +6,8 @@ var_dump(unserialize('a:2:{i:0;O:9:"exception":1:{s:16:"'."\0".'Exception'."\0".
 var_dump(unserialize('a:2:{i:0;O:9:"exception":1:{s:16:"'."\0".'Exception'."\0".'trace";s:4:"test";}i:1;r:3;}'));
 ?>
 --EXPECTF--
-array(2) {
-  [0]=>
-  object(Exception)#%d (6) {
-    ["message":protected]=>
-    string(0) ""
-    ["string":"Exception":private]=>
-    string(0) ""
-    ["code":protected]=>
-    int(0)
-    ["file":protected]=>
-    string(%d) "%s"
-    ["line":protected]=>
-    int(2)
-    ["previous":"Exception":private]=>
-    NULL
-  }
-  [1]=>
-  string(4) "test"
-}
-
-Notice: unserialize(): Error at offset %d of %d bytes in %sbug70963.php on line 3
-bool(false)
+Fatal error: Uncaught TypeError: Cannot assign string to property Exception::$trace of type array in %s:%d
+Stack trace:
+#0 %s(%d): unserialize('a:2:{i:0;O:9:"e...')
+#1 {main}
+  thrown in %s on line %d
index 530b6cf29b8b510b831f400f9dc9af9ffff26308..c037889c41c5e741cc45c8a0d958e00493c8e2c1 100644 (file)
@@ -37,7 +37,7 @@ string(183) "Class [ <internal:Core> class stdClass ] {
 }
 
 "
-string(2159) "Class [ <internal:Core> class Exception implements Throwable, Stringable ] {
+string(2166) "Class [ <internal:Core> class Exception implements Throwable, Stringable ] {
 
   - Constants [0] {
   }
@@ -54,7 +54,7 @@ string(2159) "Class [ <internal:Core> class Exception implements Throwable, Stri
     Property [ protected $code = 0 ]
     Property [ protected $file = NULL ]
     Property [ protected $line = NULL ]
-    Property [ private $trace = NULL ]
+    Property [ private array $trace = Array ]
     Property [ private $previous = NULL ]
   }