From: Nikita Popov Date: Thu, 1 Oct 2020 14:12:56 +0000 (+0200) Subject: Fix bug #65387 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=afab9eb48c883766b7870f76f2e2b0a4bd575786;p=php Fix bug #65387 Add GC support to dual_it. This is still missing AppendIterator support. --- diff --git a/NEWS b/NEWS index b5f816a055..57892d8bb6 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.0.0rc2 +- SPL. + . Fixed bug #65387 (Circular references in SPL iterators are not garbage + collected). (Nikita) 01 Oct 2020, PHP 8.0.0rc1 diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 4735a257a8..c73134e9ae 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -2119,6 +2119,52 @@ static void spl_dual_it_free_storage(zend_object *_object) } /* }}} */ +static HashTable *spl_dual_it_get_gc(zend_object *obj, zval **table, int *n) +{ + spl_dual_it_object *object = spl_dual_it_from_obj(obj); + zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); + + if (!Z_ISUNDEF(object->inner.zobject)) { + zend_get_gc_buffer_add_zval(gc_buffer, &object->inner.zobject); + } + + switch (object->dit_type) { + case DIT_Unknown: + case DIT_Default: + case DIT_IteratorIterator: + case DIT_NoRewindIterator: + case DIT_InfiniteIterator: + case DIT_LimitIterator: + case DIT_RegexIterator: + case DIT_RecursiveRegexIterator: + /* Nothing to do */ + break; + case DIT_AppendIterator: + // TODO + /*zend_get_gc_buffer_add_obj(gc_buffer, &object->u.append.iterator->std); + if (Z_TYPE(object->u.append.zarrayit) != IS_UNDEF) { + zend_get_gc_buffer_add_zval(gc_buffer, &object->u.append.zarrayit); + }*/ + break; + case DIT_CachingIterator: + case DIT_RecursiveCachingIterator: + zend_get_gc_buffer_add_zval(gc_buffer, &object->u.caching.zcache); + break; + case DIT_CallbackFilterIterator: + case DIT_RecursiveCallbackFilterIterator: + if (object->u.cbfilter) { + zend_get_gc_buffer_add_zval(gc_buffer, &object->u.cbfilter->fci.function_name); + if (object->u.cbfilter->fci.object) { + zend_get_gc_buffer_add_obj(gc_buffer, object->u.cbfilter->fci.object); + } + } + break; + } + + zend_get_gc_buffer_use(gc_buffer, table, n); + return zend_std_get_properties(obj); +} + /* {{{ spl_dual_it_new */ static zend_object *spl_dual_it_new(zend_class_entry *class_type) { @@ -3191,6 +3237,7 @@ PHP_MINIT_FUNCTION(spl_iterators) spl_handlers_dual_it.clone_obj = NULL; spl_handlers_dual_it.dtor_obj = spl_dual_it_dtor; spl_handlers_dual_it.free_obj = spl_dual_it_free_storage; + spl_handlers_dual_it.get_gc = spl_dual_it_get_gc; spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator; diff --git a/ext/spl/tests/bug65387.phpt b/ext/spl/tests/bug65387.phpt new file mode 100644 index 0000000000..75678254bd --- /dev/null +++ b/ext/spl/tests/bug65387.phpt @@ -0,0 +1,54 @@ +--TEST-- +Bug #67387: Circular references in SPL iterators are not garbage collected +--FILE-- +it = new CallbackFilterIterator($it, function($elem) { + return true; + }); + } +}; + +// Recursive callback +$it = new RecursiveArrayIterator([1, 2, 3]); +$it2 = new RecursiveCallbackFilterIterator($it, function($elem) use(&$it2) { + return true; +}); + +// Cache +$it = new ArrayIterator(); +$it2 = new CachingIterator($it, CachingIterator::FULL_CACHE); +$it2[] = $it2; +$it2->next(); + +// Recursive cache +$it = new RecursiveArrayIterator(); +$it2 = new RecursiveCachingIterator($it, CachingIterator::FULL_CACHE); +$it2[] = $it2; +$it2->next(); + +// Append +/* TODO +$it = new ArrayIterator(); +$it2 = new AppendIterator(); +$it[] = $it2; +$it2->append($it); + */ + +?> +===DONE=== +--EXPECT-- +===DONE===