Skip to content

Commit afab9eb

Browse files
committed
Fix bug #65387
Add GC support to dual_it. This is still missing AppendIterator support.
1 parent 0a84fba commit afab9eb

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.0.0rc2
44

5+
- SPL.
6+
. Fixed bug #65387 (Circular references in SPL iterators are not garbage
7+
collected). (Nikita)
58

69
01 Oct 2020, PHP 8.0.0rc1
710

ext/spl/spl_iterators.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,6 +2119,52 @@ static void spl_dual_it_free_storage(zend_object *_object)
21192119
}
21202120
/* }}} */
21212121

2122+
static HashTable *spl_dual_it_get_gc(zend_object *obj, zval **table, int *n)
2123+
{
2124+
spl_dual_it_object *object = spl_dual_it_from_obj(obj);
2125+
zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
2126+
2127+
if (!Z_ISUNDEF(object->inner.zobject)) {
2128+
zend_get_gc_buffer_add_zval(gc_buffer, &object->inner.zobject);
2129+
}
2130+
2131+
switch (object->dit_type) {
2132+
case DIT_Unknown:
2133+
case DIT_Default:
2134+
case DIT_IteratorIterator:
2135+
case DIT_NoRewindIterator:
2136+
case DIT_InfiniteIterator:
2137+
case DIT_LimitIterator:
2138+
case DIT_RegexIterator:
2139+
case DIT_RecursiveRegexIterator:
2140+
/* Nothing to do */
2141+
break;
2142+
case DIT_AppendIterator:
2143+
// TODO
2144+
/*zend_get_gc_buffer_add_obj(gc_buffer, &object->u.append.iterator->std);
2145+
if (Z_TYPE(object->u.append.zarrayit) != IS_UNDEF) {
2146+
zend_get_gc_buffer_add_zval(gc_buffer, &object->u.append.zarrayit);
2147+
}*/
2148+
break;
2149+
case DIT_CachingIterator:
2150+
case DIT_RecursiveCachingIterator:
2151+
zend_get_gc_buffer_add_zval(gc_buffer, &object->u.caching.zcache);
2152+
break;
2153+
case DIT_CallbackFilterIterator:
2154+
case DIT_RecursiveCallbackFilterIterator:
2155+
if (object->u.cbfilter) {
2156+
zend_get_gc_buffer_add_zval(gc_buffer, &object->u.cbfilter->fci.function_name);
2157+
if (object->u.cbfilter->fci.object) {
2158+
zend_get_gc_buffer_add_obj(gc_buffer, object->u.cbfilter->fci.object);
2159+
}
2160+
}
2161+
break;
2162+
}
2163+
2164+
zend_get_gc_buffer_use(gc_buffer, table, n);
2165+
return zend_std_get_properties(obj);
2166+
}
2167+
21222168
/* {{{ spl_dual_it_new */
21232169
static zend_object *spl_dual_it_new(zend_class_entry *class_type)
21242170
{
@@ -3191,6 +3237,7 @@ PHP_MINIT_FUNCTION(spl_iterators)
31913237
spl_handlers_dual_it.clone_obj = NULL;
31923238
spl_handlers_dual_it.dtor_obj = spl_dual_it_dtor;
31933239
spl_handlers_dual_it.free_obj = spl_dual_it_free_storage;
3240+
spl_handlers_dual_it.get_gc = spl_dual_it_get_gc;
31943241

31953242
spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator;
31963243

ext/spl/tests/bug65387.phpt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
Bug #67387: Circular references in SPL iterators are not garbage collected
3+
--FILE--
4+
<?php
5+
6+
$it = new ArrayIterator([1, 2, 3]);
7+
// Inner.
8+
$it[] = $it;
9+
10+
// Callback
11+
$it2 = new CallbackFilterIterator($it, function($elem) use(&$it2) {
12+
return true;
13+
});
14+
15+
// Callback object
16+
new class {
17+
public function __construct() {
18+
$it = new ArrayIterator([1, 2, 3]);
19+
$this->it = new CallbackFilterIterator($it, function($elem) {
20+
return true;
21+
});
22+
}
23+
};
24+
25+
// Recursive callback
26+
$it = new RecursiveArrayIterator([1, 2, 3]);
27+
$it2 = new RecursiveCallbackFilterIterator($it, function($elem) use(&$it2) {
28+
return true;
29+
});
30+
31+
// Cache
32+
$it = new ArrayIterator();
33+
$it2 = new CachingIterator($it, CachingIterator::FULL_CACHE);
34+
$it2[] = $it2;
35+
$it2->next();
36+
37+
// Recursive cache
38+
$it = new RecursiveArrayIterator();
39+
$it2 = new RecursiveCachingIterator($it, CachingIterator::FULL_CACHE);
40+
$it2[] = $it2;
41+
$it2->next();
42+
43+
// Append
44+
/* TODO
45+
$it = new ArrayIterator();
46+
$it2 = new AppendIterator();
47+
$it[] = $it2;
48+
$it2->append($it);
49+
*/
50+
51+
?>
52+
===DONE===
53+
--EXPECT--
54+
===DONE===

0 commit comments

Comments
 (0)