From 1fa6f03265467ec1b8b9f898182792ec936dbd74 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 16 Jan 2020 15:30:24 +0100 Subject: [PATCH] Fix reflection leak if type inside type list is resolved --- ext/reflection/php_reflection.c | 25 +++++++------------------ ext/reflection/tests/bug78774.phpt | 6 ++++++ 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 240ea4473c..73ab2b8969 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -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)); } } diff --git a/ext/reflection/tests/bug78774.phpt b/ext/reflection/tests/bug78774.phpt index 1e419b1138..7f72039e07 100644 --- a/ext/reflection/tests/bug78774.phpt +++ b/ext/reflection/tests/bug78774.phpt @@ -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" -- 2.40.0