From 72c581b12fe710e4583d93f387c826aef7d4d19e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 12 Dec 2024 19:00:41 +0100 Subject: [PATCH] Implement acyclic object tracking Acyclic objects don't need to be added to the GC. We know an object is acyclic if all properties are typed as acyclic, and the object does not have any dynamic properties. This is possible to track at runtime with minimal overhead. Fixes GH-17127 --- Zend/tests/gc/gc_045.phpt | 6 +++++ Zend/zend_API.c | 27 +++++++++++++++++++++ Zend/zend_closures.c | 3 +++ Zend/zend_compile.h | 5 +++- Zend/zend_fibers.c | 1 + Zend/zend_generators.c | 1 + Zend/zend_inheritance.c | 4 ++++ Zend/zend_object_handlers.c | 2 ++ Zend/zend_objects.c | 3 +++ Zend/zend_weakrefs.c | 1 + ext/curl/interface.c | 1 + ext/curl/multi.c | 1 + ext/dom/php_dom.c | 2 ++ ext/pdo/pdo_dbh.c | 1 + ext/pdo/pdo_stmt.c | 1 + ext/reflection/php_reflection.c | 32 +++++++++++++++++++++++++ ext/reflection/php_reflection.stub.php | 2 ++ ext/reflection/php_reflection_arginfo.h | 6 ++++- ext/simplexml/simplexml.c | 1 + ext/sockets/sockets.c | 1 + ext/spl/spl_array.c | 2 ++ ext/spl/spl_dllist.c | 1 + ext/spl/spl_fixedarray.c | 1 + ext/spl/spl_heap.c | 2 ++ ext/spl/spl_iterators.c | 2 ++ ext/spl/spl_observer.c | 2 ++ ext/sqlite3/sqlite3.c | 1 + ext/xml/xml.c | 1 + ext/xsl/php_xsl.c | 1 + 29 files changed, 112 insertions(+), 2 deletions(-) diff --git a/Zend/tests/gc/gc_045.phpt b/Zend/tests/gc/gc_045.phpt index 1762be5db1ad9..cbb1fc71e79f9 100644 --- a/Zend/tests/gc/gc_045.phpt +++ b/Zend/tests/gc/gc_045.phpt @@ -11,6 +11,9 @@ class GlobalData class Value { + /* Force object to be added to GC, even though it is acyclic. */ + public $dummy; + public function __destruct() { new Bar(); @@ -19,6 +22,9 @@ class Value class Bar { + /* Force object to be added to GC, even though it is acyclic. */ + public $dummy; + public function __construct() { GlobalData::$bar = $this; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index fd5b7c8db7966..6f7f0f1b323c0 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -4494,6 +4494,27 @@ static zend_always_inline bool is_persistent_class(zend_class_entry *ce) { && ce->info.internal.module->type == MODULE_PERSISTENT; } +static bool zend_type_may_be_cyclic(zend_type type) +{ + if (!ZEND_TYPE_IS_SET(type)) { + return true; + } + + if (!ZEND_TYPE_IS_COMPLEX(type)) { + return ZEND_TYPE_PURE_MASK(type) & (MAY_BE_OBJECT|MAY_BE_ARRAY); + } else if (ZEND_TYPE_IS_UNION(type)) { + zend_type *list_type; + ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { + if (zend_type_may_be_cyclic(*list_type)) { + return true; + } + } ZEND_TYPE_LIST_FOREACH_END(); + return false; + } + + return true; +} + ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */ { zend_property_info *property_info, *property_info_ptr; @@ -4506,6 +4527,12 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z } } + if (!(access_type & ZEND_ACC_STATIC) + && !(ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC) + && zend_type_may_be_cyclic(type)) { + ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; + } + if (ce->type == ZEND_INTERNAL_CLASS) { property_info = pemalloc(sizeof(zend_property_info), 1); } else { diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 629aa7d51a840..54899f25945a6 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -705,6 +705,9 @@ void zend_register_closure_ce(void) /* {{{ */ zend_ce_closure = register_class_Closure(); zend_ce_closure->create_object = zend_closure_new; zend_ce_closure->default_object_handlers = &closure_handlers; + /* FIXME: Potentially improve during construction of closure? static closures + * not binding by references can't be cyclic. */ + zend_ce_closure->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&closure_handlers, &std_object_handlers, sizeof(zend_object_handlers)); closure_handlers.free_obj = zend_closure_free_storage; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 1eaf3ef686e79..5f3634ae4b894 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -267,7 +267,7 @@ typedef struct _zend_oparray_context { #define ZEND_ACC_PROTECTED_SET (1 << 11) /* | | X | */ #define ZEND_ACC_PRIVATE_SET (1 << 12) /* | | X | */ /* | | | */ -/* Class Flags (unused: 30,31) | | | */ +/* Class Flags (unused: 31) | | | */ /* =========== | | | */ /* | | | */ /* Special class types | | | */ @@ -333,6 +333,9 @@ typedef struct _zend_oparray_context { /* Class cannot be serialized or unserialized | | | */ #define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */ /* | | | */ +/* Object may be the root of a cycle | | | */ +#define ZEND_ACC_MAY_BE_CYCLIC (1 << 30) /* X | | | */ +/* | | | */ /* Function Flags (unused: 29-30) | | | */ /* ============== | | | */ /* | | | */ diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index 97b7cdcc911b7..da0a2a5f16eb1 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -1107,6 +1107,7 @@ void zend_register_fiber_ce(void) zend_ce_fiber = register_class_Fiber(); zend_ce_fiber->create_object = zend_fiber_object_create; zend_ce_fiber->default_object_handlers = &zend_fiber_handlers; + zend_ce_fiber->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; zend_fiber_handlers = std_object_handlers; zend_fiber_handlers.dtor_obj = zend_fiber_object_destroy; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index a6ea91a7425b9..d847da5e93942 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -1215,6 +1215,7 @@ void zend_register_generator_ce(void) /* {{{ */ /* get_iterator has to be assigned *after* implementing the interface */ zend_ce_generator->get_iterator = zend_generator_get_iterator; zend_ce_generator->default_object_handlers = &zend_generator_handlers; + zend_ce_generator->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&zend_generator_handlers, &std_object_handlers, sizeof(zend_object_handlers)); zend_generator_handlers.free_obj = zend_generator_free_storage; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 3557b14bb9740..76aed3fea04c2 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1810,6 +1810,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par ce->parent = parent_ce; ce->default_object_handlers = parent_ce->default_object_handlers; ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT; + ce->ce_flags |= (parent_ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC); /* Inherit properties */ if (parent_ce->default_properties_count) { @@ -2832,6 +2833,9 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent if (!traits[i]) { continue; } + + ce->ce_flags |= (traits[i]->ce_flags & ZEND_ACC_MAY_BE_CYCLIC); + ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) { uint32_t flags = property_info->flags; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 0709d05580dc8..8aa5c243110d5 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -70,6 +70,8 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj) /* {{{ zend_class_entry *ce = zobj->ce; int i; + GC_TYPE_INFO(zobj) &= ~(GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT); + zobj->properties = zend_new_array(ce->default_properties_count); if (ce->default_properties_count) { zend_hash_real_init_mixed(zobj->properties); diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index fd0e97c5f4131..5dbd411c623f8 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -31,6 +31,9 @@ static zend_always_inline void _zend_object_std_init(zend_object *object, zend_c { GC_SET_REFCOUNT(object, 1); GC_TYPE_INFO(object) = GC_OBJECT; + if (!(ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC)) { + GC_TYPE_INFO(object) |= (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT); + } object->ce = ce; object->extra_flags = 0; object->handlers = ce->default_object_handlers; diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c index cf363cd12595c..2dce20257e689 100644 --- a/Zend/zend_weakrefs.c +++ b/Zend/zend_weakrefs.c @@ -788,6 +788,7 @@ void zend_register_weakref_ce(void) /* {{{ */ zend_ce_weakmap->create_object = zend_weakmap_create_object; zend_ce_weakmap->get_iterator = zend_weakmap_get_iterator; zend_ce_weakmap->default_object_handlers = &zend_weakmap_handlers; + zend_ce_weakmap->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&zend_weakmap_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); zend_weakmap_handlers.offset = XtOffsetOf(zend_weakmap, std); diff --git a/ext/curl/interface.c b/ext/curl/interface.c index aba5273d5496c..328ea4e0a674a 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -395,6 +395,7 @@ PHP_MINIT_FUNCTION(curl) curl_ce = register_class_CurlHandle(); curl_ce->create_object = curl_create_object; curl_ce->default_object_handlers = &curl_object_handlers; + curl_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&curl_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); curl_object_handlers.offset = XtOffsetOf(php_curl, std); diff --git a/ext/curl/multi.c b/ext/curl/multi.c index 6456cf6f813e4..244c3b078a752 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -606,6 +606,7 @@ static zend_object_handlers curl_multi_handlers; void curl_multi_register_handlers(void) { curl_multi_ce->create_object = curl_multi_create_object; curl_multi_ce->default_object_handlers = &curl_multi_handlers; + curl_multi_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&curl_multi_handlers, &std_object_handlers, sizeof(zend_object_handlers)); curl_multi_handlers.offset = XtOffsetOf(php_curlm, std); diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 21741166c61aa..b92f2d843d4b6 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1292,6 +1292,7 @@ PHP_MINIT_FUNCTION(dom) dom_xpath_class_entry = register_class_DOMXPath(); dom_xpath_class_entry->create_object = dom_xpath_objects_new; dom_xpath_class_entry->default_object_handlers = &dom_xpath_object_handlers; + dom_xpath_class_entry->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; zend_hash_init(&dom_xpath_prop_handlers, 0, NULL, NULL, true); DOM_REGISTER_PROP_HANDLER(&dom_xpath_prop_handlers, "document", dom_xpath_document_read, NULL); @@ -1301,6 +1302,7 @@ PHP_MINIT_FUNCTION(dom) dom_modern_xpath_class_entry = register_class_Dom_XPath(); dom_modern_xpath_class_entry->create_object = dom_xpath_objects_new; dom_modern_xpath_class_entry->default_object_handlers = &dom_xpath_object_handlers; + dom_modern_xpath_class_entry->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; zend_hash_add_new_ptr(&classes, dom_modern_xpath_class_entry->name, &dom_xpath_prop_handlers); #endif diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 782639be0758e..611c8a490b96f 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1449,6 +1449,7 @@ void pdo_dbh_init(int module_number) pdo_dbh_ce = register_class_PDO(); pdo_dbh_ce->create_object = pdo_dbh_new; pdo_dbh_ce->default_object_handlers = &pdo_dbh_object_handlers; + pdo_dbh_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); pdo_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_object_t, std); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index a39b7a3b06804..df131685a16a1 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2491,6 +2491,7 @@ void pdo_stmt_init(void) pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get; pdo_dbstmt_ce->create_object = pdo_dbstmt_new; pdo_dbstmt_ce->default_object_handlers = &pdo_dbstmt_object_handlers; + pdo_dbstmt_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index f5e463699b1b5..9b60374f8de89 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -4343,6 +4343,16 @@ ZEND_METHOD(ReflectionClass, getAttributes) } /* }}} */ +ZEND_METHOD(ReflectionClass, mayBeCyclic) +{ + reflection_object *intern; + zend_class_entry *ce; + + GET_REFLECTION_OBJECT_PTR(ce); + + RETURN_BOOL(ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC); +} + /* {{{ Returns the class' constructor if there is one, NULL otherwise */ ZEND_METHOD(ReflectionClass, getConstructor) { @@ -7682,91 +7692,113 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr); reflection_function_abstract_ptr->default_object_handlers = &reflection_object_handlers; + reflection_function_abstract_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_function_abstract_ptr->create_object = reflection_objects_new; reflection_function_ptr = register_class_ReflectionFunction(reflection_function_abstract_ptr); reflection_function_ptr->create_object = reflection_objects_new; reflection_function_ptr->default_object_handlers = &reflection_object_handlers; + reflection_function_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_generator_ptr = register_class_ReflectionGenerator(); reflection_generator_ptr->create_object = reflection_objects_new; reflection_generator_ptr->default_object_handlers = &reflection_object_handlers; + reflection_generator_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr); reflection_parameter_ptr->create_object = reflection_objects_new; reflection_parameter_ptr->default_object_handlers = &reflection_object_handlers; + reflection_parameter_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_type_ptr = register_class_ReflectionType(zend_ce_stringable); reflection_type_ptr->create_object = reflection_objects_new; reflection_type_ptr->default_object_handlers = &reflection_object_handlers; + reflection_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_named_type_ptr = register_class_ReflectionNamedType(reflection_type_ptr); reflection_named_type_ptr->create_object = reflection_objects_new; reflection_named_type_ptr->default_object_handlers = &reflection_object_handlers; + reflection_named_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_union_type_ptr = register_class_ReflectionUnionType(reflection_type_ptr); reflection_union_type_ptr->create_object = reflection_objects_new; reflection_union_type_ptr->default_object_handlers = &reflection_object_handlers; + reflection_union_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_intersection_type_ptr = register_class_ReflectionIntersectionType(reflection_type_ptr); reflection_intersection_type_ptr->create_object = reflection_objects_new; reflection_intersection_type_ptr->default_object_handlers = &reflection_object_handlers; + reflection_intersection_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_method_ptr = register_class_ReflectionMethod(reflection_function_abstract_ptr); reflection_method_ptr->create_object = reflection_objects_new; reflection_method_ptr->default_object_handlers = &reflection_object_handlers; + reflection_method_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_class_ptr = register_class_ReflectionClass(reflector_ptr); reflection_class_ptr->create_object = reflection_objects_new; reflection_class_ptr->default_object_handlers = &reflection_object_handlers; + reflection_class_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_object_ptr = register_class_ReflectionObject(reflection_class_ptr); reflection_object_ptr->create_object = reflection_objects_new; reflection_object_ptr->default_object_handlers = &reflection_object_handlers; + reflection_object_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr); reflection_property_ptr->create_object = reflection_objects_new; reflection_property_ptr->default_object_handlers = &reflection_object_handlers; + reflection_property_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr); reflection_class_constant_ptr->create_object = reflection_objects_new; reflection_class_constant_ptr->default_object_handlers = &reflection_object_handlers; + reflection_class_constant_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_extension_ptr = register_class_ReflectionExtension(reflector_ptr); reflection_extension_ptr->create_object = reflection_objects_new; reflection_extension_ptr->default_object_handlers = &reflection_object_handlers; + reflection_extension_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_zend_extension_ptr = register_class_ReflectionZendExtension(reflector_ptr); reflection_zend_extension_ptr->create_object = reflection_objects_new; reflection_zend_extension_ptr->default_object_handlers = &reflection_object_handlers; + reflection_zend_extension_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_reference_ptr = register_class_ReflectionReference(); reflection_reference_ptr->create_object = reflection_objects_new; reflection_reference_ptr->default_object_handlers = &reflection_object_handlers; + reflection_reference_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_attribute_ptr = register_class_ReflectionAttribute(reflector_ptr); reflection_attribute_ptr->create_object = reflection_objects_new; reflection_attribute_ptr->default_object_handlers = &reflection_object_handlers; + reflection_attribute_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_enum_ptr = register_class_ReflectionEnum(reflection_class_ptr); reflection_enum_ptr->create_object = reflection_objects_new; reflection_enum_ptr->default_object_handlers = &reflection_object_handlers; + reflection_enum_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_enum_unit_case_ptr = register_class_ReflectionEnumUnitCase(reflection_class_constant_ptr); reflection_enum_unit_case_ptr->create_object = reflection_objects_new; reflection_enum_unit_case_ptr->default_object_handlers = &reflection_object_handlers; + reflection_enum_unit_case_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_enum_backed_case_ptr = register_class_ReflectionEnumBackedCase(reflection_enum_unit_case_ptr); reflection_enum_backed_case_ptr->create_object = reflection_objects_new; reflection_enum_backed_case_ptr->default_object_handlers = &reflection_object_handlers; + reflection_enum_backed_case_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_fiber_ptr = register_class_ReflectionFiber(); reflection_fiber_ptr->create_object = reflection_objects_new; reflection_fiber_ptr->default_object_handlers = &reflection_object_handlers; + reflection_fiber_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr); reflection_constant_ptr->create_object = reflection_objects_new; reflection_constant_ptr->default_object_handlers = &reflection_object_handlers; + reflection_constant_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; reflection_property_hook_type_ptr = register_class_PropertyHookType(); diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index be511d7ee14cd..b33c27b2af2d1 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -432,6 +432,8 @@ public function getNamespaceName(): string {} public function getShortName(): string {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function mayBeCyclic(): bool {} } class ReflectionObject extends ReflectionClass diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index d78a685dde9c9..7bc073f1f5459 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3c6be99bb36965139464925a618cb0bf03affa62 */ + * Stub hash: e2086e92426bd71218575f5a4c6dd0fea7049008 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) @@ -366,6 +366,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClass_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionClass_mayBeCyclic arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionObject___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) ZEND_END_ARG_INFO() @@ -847,6 +849,7 @@ ZEND_METHOD(ReflectionClass, inNamespace); ZEND_METHOD(ReflectionClass, getNamespaceName); ZEND_METHOD(ReflectionClass, getShortName); ZEND_METHOD(ReflectionClass, getAttributes); +ZEND_METHOD(ReflectionClass, mayBeCyclic); ZEND_METHOD(ReflectionObject, __construct); ZEND_METHOD(ReflectionProperty, __construct); ZEND_METHOD(ReflectionProperty, __toString); @@ -1139,6 +1142,7 @@ static const zend_function_entry class_ReflectionClass_methods[] = { ZEND_ME(ReflectionClass, getNamespaceName, arginfo_class_ReflectionClass_getNamespaceName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, getShortName, arginfo_class_ReflectionClass_getShortName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, getAttributes, arginfo_class_ReflectionClass_getAttributes, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, mayBeCyclic, arginfo_class_ReflectionClass_mayBeCyclic, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index a962028d30865..5a627b43324e5 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -2654,6 +2654,7 @@ PHP_MINIT_FUNCTION(simplexml) ce_SimpleXMLElement = register_class_SimpleXMLElement(zend_ce_stringable, zend_ce_countable, spl_ce_RecursiveIterator); ce_SimpleXMLElement->create_object = sxe_object_new; ce_SimpleXMLElement->default_object_handlers = &sxe_object_handlers; + ce_SimpleXMLElement->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; ce_SimpleXMLElement->get_iterator = php_sxe_get_iterator; memcpy(&sxe_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 940b1621f75d0..e31cc7cf4b44c 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -455,6 +455,7 @@ static PHP_MINIT_FUNCTION(sockets) socket_ce = register_class_Socket(); socket_ce->create_object = socket_create_object; socket_ce->default_object_handlers = &socket_object_handlers; + socket_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&socket_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); socket_object_handlers.offset = XtOffsetOf(php_socket, std); diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index af886944bc49e..a77f110c47e55 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1883,6 +1883,7 @@ PHP_MINIT_FUNCTION(spl_array) spl_ce_ArrayObject = register_class_ArrayObject(zend_ce_aggregate, zend_ce_arrayaccess, zend_ce_serializable, zend_ce_countable); spl_ce_ArrayObject->create_object = spl_array_object_new; spl_ce_ArrayObject->default_object_handlers = &spl_handler_ArrayObject; + spl_ce_ArrayObject->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&spl_handler_ArrayObject, &std_object_handlers, sizeof(zend_object_handlers)); @@ -1909,6 +1910,7 @@ PHP_MINIT_FUNCTION(spl_array) spl_ce_ArrayIterator = register_class_ArrayIterator(spl_ce_SeekableIterator, zend_ce_arrayaccess, zend_ce_serializable, zend_ce_countable); spl_ce_ArrayIterator->create_object = spl_array_object_new; spl_ce_ArrayIterator->default_object_handlers = &spl_handler_ArrayObject; + spl_ce_ArrayIterator->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator; spl_ce_RecursiveArrayIterator = register_class_RecursiveArrayIterator(spl_ce_ArrayIterator, spl_ce_RecursiveIterator); diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 5a78db2921a81..cf82c8000c450 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -1256,6 +1256,7 @@ PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */ ); spl_ce_SplDoublyLinkedList->create_object = spl_dllist_object_new; spl_ce_SplDoublyLinkedList->default_object_handlers = &spl_handler_SplDoublyLinkedList; + spl_ce_SplDoublyLinkedList->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator; memcpy(&spl_handler_SplDoublyLinkedList, &std_object_handlers, sizeof(zend_object_handlers)); diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 5d7949308a303..a25e389861cf1 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -964,6 +964,7 @@ PHP_MINIT_FUNCTION(spl_fixedarray) zend_ce_aggregate, zend_ce_arrayaccess, zend_ce_countable, php_json_serializable_ce); spl_ce_SplFixedArray->create_object = spl_fixedarray_new; spl_ce_SplFixedArray->default_object_handlers = &spl_handler_SplFixedArray; + spl_ce_SplFixedArray->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator; memcpy(&spl_handler_SplFixedArray, &std_object_handlers, sizeof(zend_object_handlers)); diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index d4450da42009c..52d5c9783a074 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -1141,6 +1141,7 @@ PHP_MINIT_FUNCTION(spl_heap) /* {{{ */ spl_ce_SplHeap = register_class_SplHeap(zend_ce_iterator, zend_ce_countable); spl_ce_SplHeap->create_object = spl_heap_object_new; spl_ce_SplHeap->default_object_handlers = &spl_handler_SplHeap; + spl_ce_SplHeap->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; spl_ce_SplHeap->get_iterator = spl_heap_get_iterator; memcpy(&spl_handler_SplHeap, &std_object_handlers, sizeof(zend_object_handlers)); @@ -1162,6 +1163,7 @@ PHP_MINIT_FUNCTION(spl_heap) /* {{{ */ spl_ce_SplPriorityQueue = register_class_SplPriorityQueue(zend_ce_iterator, zend_ce_countable); spl_ce_SplPriorityQueue->create_object = spl_heap_object_new; spl_ce_SplPriorityQueue->default_object_handlers = &spl_handler_SplPriorityQueue; + spl_ce_SplPriorityQueue->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; spl_ce_SplPriorityQueue->get_iterator = spl_pqueue_get_iterator; memcpy(&spl_handler_SplPriorityQueue, &std_object_handlers, sizeof(zend_object_handlers)); diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index d4e40bf6b684a..a0360ef556d62 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -3108,6 +3108,7 @@ PHP_MINIT_FUNCTION(spl_iterators) spl_ce_RecursiveIteratorIterator = register_class_RecursiveIteratorIterator(spl_ce_OuterIterator); spl_ce_RecursiveIteratorIterator->create_object = spl_RecursiveIteratorIterator_new; spl_ce_RecursiveIteratorIterator->default_object_handlers = &spl_handlers_rec_it_it; + spl_ce_RecursiveIteratorIterator->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator; memcpy(&spl_handlers_rec_it_it, &std_object_handlers, sizeof(zend_object_handlers)); @@ -3127,6 +3128,7 @@ PHP_MINIT_FUNCTION(spl_iterators) spl_ce_IteratorIterator = register_class_IteratorIterator(spl_ce_OuterIterator); spl_ce_IteratorIterator->create_object = spl_dual_it_new; spl_ce_IteratorIterator->default_object_handlers = &spl_handlers_dual_it; + spl_ce_IteratorIterator->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; spl_ce_FilterIterator = register_class_FilterIterator(spl_ce_IteratorIterator); spl_ce_FilterIterator->create_object = spl_dual_it_new; diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 5222fe2a7fa4d..a3847bed048e8 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -1379,6 +1379,7 @@ PHP_MINIT_FUNCTION(spl_observer) spl_ce_SplObjectStorage = register_class_SplObjectStorage(zend_ce_countable, spl_ce_SeekableIterator, zend_ce_serializable, zend_ce_arrayaccess); spl_ce_SplObjectStorage->create_object = spl_SplObjectStorage_new; spl_ce_SplObjectStorage->default_object_handlers = &spl_handler_SplObjectStorage; + spl_ce_SplObjectStorage->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&spl_handler_SplObjectStorage, &std_object_handlers, sizeof(zend_object_handlers)); @@ -1395,6 +1396,7 @@ PHP_MINIT_FUNCTION(spl_observer) spl_ce_MultipleIterator = register_class_MultipleIterator(zend_ce_iterator); spl_ce_MultipleIterator->create_object = spl_SplObjectStorage_new; spl_ce_MultipleIterator->default_object_handlers = &spl_handler_SplObjectStorage; + spl_ce_MultipleIterator->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; return SUCCESS; } diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 01b8af435b633..e7200b65355cd 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -2411,6 +2411,7 @@ PHP_MINIT_FUNCTION(sqlite3) php_sqlite3_sc_entry = register_class_SQLite3(); php_sqlite3_sc_entry->create_object = php_sqlite3_object_new; php_sqlite3_sc_entry->default_object_handlers = &sqlite3_object_handlers; + php_sqlite3_sc_entry->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; /* Register SQLite 3 Prepared Statement Class */ sqlite3_stmt_object_handlers.offset = XtOffsetOf(php_sqlite3_stmt, zo); diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 7eca5c0795e2a..d034898f861c9 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -228,6 +228,7 @@ PHP_MINIT_FUNCTION(xml) xml_parser_ce = register_class_XMLParser(); xml_parser_ce->create_object = xml_parser_create_object; xml_parser_ce->default_object_handlers = &xml_parser_object_handlers; + xml_parser_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; memcpy(&xml_parser_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); xml_parser_object_handlers.offset = XtOffsetOf(xml_parser, std); diff --git a/ext/xsl/php_xsl.c b/ext/xsl/php_xsl.c index dec7eb501eb2f..8c45429269d72 100644 --- a/ext/xsl/php_xsl.c +++ b/ext/xsl/php_xsl.c @@ -278,6 +278,7 @@ PHP_MINIT_FUNCTION(xsl) xsl_xsltprocessor_class_entry = register_class_XSLTProcessor(); xsl_xsltprocessor_class_entry->create_object = xsl_objects_new; xsl_xsltprocessor_class_entry->default_object_handlers = &xsl_object_handlers; + xsl_xsltprocessor_class_entry->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC; #ifdef HAVE_XSL_EXSLT exsltRegisterAll();