]> granicus.if.org Git - php/commitdiff
Fix reflection leak if type inside type list is resolved
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 16 Jan 2020 14:30:24 +0000 (15:30 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 16 Jan 2020 14:30:24 +0000 (15:30 +0100)
ext/reflection/php_reflection.c
ext/reflection/tests/bug78774.phpt

index 240ea4473c929f7670445626f7b00e0a37d7d9c4..73ab2b89694241ef8f1c5e28e0ad9d684480ead6 100644 (file)
@@ -231,14 +231,7 @@ static void reflection_free_objects_storage(zend_object *object) /* {{{ */
                case REF_TYPE_TYPE:
                {
                        type_reference *type_ref = intern->ptr;
-                       if (ZEND_TYPE_HAS_LIST(type_ref->type)) {
-                               void *entry;
-                               ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type_ref->type), entry) {
-                                       if (ZEND_TYPE_LIST_IS_NAME(entry)) {
-                                               zend_string_release(ZEND_TYPE_LIST_GET_NAME(entry));
-                                       }
-                               } ZEND_TYPE_LIST_FOREACH_END();
-                       } else if (ZEND_TYPE_HAS_NAME(type_ref->type)) {
+                       if (ZEND_TYPE_HAS_NAME(type_ref->type)) {
                                zend_string_release(ZEND_TYPE_NAME(type_ref->type));
                        }
                        efree(type_ref);
@@ -1174,16 +1167,12 @@ static void reflection_type_factory(zend_type type, zval *object, zend_bool lega
        intern->ptr = reference;
        intern->ref_type = REF_TYPE_TYPE;
 
-       /* Property types may be resolved during the lifetime of the ReflectionType,
-        * so we need to make sure that the strings we reference are not released. */
-       if (ZEND_TYPE_HAS_LIST(type)) {
-               void *entry;
-               ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), entry) {
-                       if (ZEND_TYPE_LIST_IS_NAME(entry)) {
-                               zend_string_addref(ZEND_TYPE_LIST_GET_NAME(entry));
-                       }
-               } ZEND_TYPE_LIST_FOREACH_END();
-       } else if (ZEND_TYPE_HAS_NAME(type)) {
+       /* Property types may be resolved during the lifetime of the ReflectionType.
+        * If we reference a string, make sure it doesn't get released. However, only
+        * do this for the top-level type, as resolutions inside type lists will be
+        * fully visible to us (we'd have to do a fully copy of the type if we wanted
+        * to prevent that). */
+       if (ZEND_TYPE_HAS_NAME(type)) {
                zend_string_addref(ZEND_TYPE_NAME(type));
        }
 }
index 1e419b1138b738157c364eb6061b2d40de3277fa..7f72039e07422fc3b9ac2c503b59ae5734c4ee89 100644 (file)
@@ -5,18 +5,24 @@ Bug #78774: ReflectionNamedType on Typed Properties Crash
 
 class Test {
     public stdClass $prop;
+    public stdClass|Foo $prop2;
 }
 
 $rc = new ReflectionClass(Test::class);
 $rp = $rc->getProperty('prop');
 $rt = $rp->getType();
+$rp2 = $rc->getProperty('prop2');
+$rt2 = $rp2->getType();
 
 // Force a resolution of the property type
 $test = new Test;
 $test->prop = new stdClass;
+$test->prop2 = new stdClass;
 
 var_dump($rt->getName());
+var_dump((string) $rt2);
 
 ?>
 --EXPECT--
 string(8) "stdClass"
+string(12) "stdClass|Foo"