Skip to content

Commit 15fafcd

Browse files
committed
Expose inner dual_it iterator to GC
Moving the zend_iterator_dtor from dual_it_dtor to dual_it_free_storage exposed this GC leak in an existing test. Forward the result of the iterator get_gc to the dual_it get_gc.
1 parent 64865c6 commit 15fafcd

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

Zend/zend_gc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,12 @@ ZEND_API void zend_get_gc_buffer_grow(zend_get_gc_buffer *gc_buffer) {
16371637
gc_buffer->cur = gc_buffer->start + old_capacity;
16381638
}
16391639

1640+
ZEND_API void zend_get_gc_buffer_add_zvals(zend_get_gc_buffer *gc_buffer, zval *zvs, size_t n) {
1641+
for (size_t i = 0; i < n; i++) {
1642+
zend_get_gc_buffer_add_zval(gc_buffer, &zvs[i]);
1643+
}
1644+
}
1645+
16401646
static void zend_get_gc_buffer_release() {
16411647
zend_get_gc_buffer *gc_buffer = &EG(get_gc_buffer);
16421648
efree(gc_buffer->start);

Zend/zend_gc.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ typedef struct {
9393

9494
ZEND_API zend_get_gc_buffer *zend_get_gc_buffer_create(void);
9595
ZEND_API void zend_get_gc_buffer_grow(zend_get_gc_buffer *gc_buffer);
96+
ZEND_API void zend_get_gc_buffer_add_zvals(zend_get_gc_buffer *gc_buffer, zval *zvs, size_t n);
9697

9798
static zend_always_inline void zend_get_gc_buffer_add_zval(
9899
zend_get_gc_buffer *gc_buffer, zval *zv) {
@@ -114,6 +115,15 @@ static zend_always_inline void zend_get_gc_buffer_add_obj(
114115
gc_buffer->cur++;
115116
}
116117

118+
static zend_always_inline void zend_get_gc_buffer_add_ht(
119+
zend_get_gc_buffer *gc_buffer, HashTable *ht) {
120+
if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) {
121+
zend_get_gc_buffer_grow(gc_buffer);
122+
}
123+
ZVAL_ARR(gc_buffer->cur, ht);
124+
gc_buffer->cur++;
125+
}
126+
117127
static zend_always_inline void zend_get_gc_buffer_use(
118128
zend_get_gc_buffer *gc_buffer, zval **table, int *n) {
119129
*table = gc_buffer->start;

ext/spl/spl_iterators.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,10 +2079,6 @@ static void spl_dual_it_dtor(zend_object *_object)
20792079
zend_objects_destroy_object(_object);
20802080

20812081
spl_dual_it_free(object);
2082-
2083-
if (object->inner.iterator) {
2084-
zend_iterator_dtor(object->inner.iterator);
2085-
}
20862082
}
20872083
/* }}} */
20882084

@@ -2091,6 +2087,9 @@ static void spl_dual_it_free_storage(zend_object *_object)
20912087
{
20922088
spl_dual_it_object *object = spl_dual_it_from_obj(_object);
20932089

2090+
if (object->inner.iterator) {
2091+
zend_iterator_dtor(object->inner.iterator);
2092+
}
20942093

20952094
if (!Z_ISUNDEF(object->inner.zobject)) {
20962095
zval_ptr_dtor(&object->inner.zobject);
@@ -2137,6 +2136,17 @@ static HashTable *spl_dual_it_get_gc(zend_object *obj, zval **table, int *n)
21372136
spl_dual_it_object *object = spl_dual_it_from_obj(obj);
21382137
zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
21392138

2139+
if (object->inner.iterator && object->inner.iterator->funcs->get_gc) {
2140+
zval *inner_table;
2141+
int inner_n;
2142+
HashTable *inner_ht = object->inner.iterator->funcs->get_gc(
2143+
object->inner.iterator, &inner_table, &inner_n);
2144+
zend_get_gc_buffer_add_zvals(gc_buffer, inner_table, inner_n);
2145+
if (inner_ht) {
2146+
zend_get_gc_buffer_add_ht(gc_buffer, inner_ht);
2147+
}
2148+
}
2149+
21402150
if (!Z_ISUNDEF(object->inner.zobject)) {
21412151
zend_get_gc_buffer_add_zval(gc_buffer, &object->inner.zobject);
21422152
}

0 commit comments

Comments
 (0)