From 15fafcd6648052bcbf426e4ebf60ae00a07eaaae Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 8 Jun 2021 16:52:23 +0200 Subject: [PATCH] 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. --- Zend/zend_gc.c | 6 ++++++ Zend/zend_gc.h | 10 ++++++++++ ext/spl/spl_iterators.c | 18 ++++++++++++++---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index f0c9a847b8c..3e66dae10db 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -1637,6 +1637,12 @@ ZEND_API void zend_get_gc_buffer_grow(zend_get_gc_buffer *gc_buffer) { gc_buffer->cur = gc_buffer->start + old_capacity; } +ZEND_API void zend_get_gc_buffer_add_zvals(zend_get_gc_buffer *gc_buffer, zval *zvs, size_t n) { + for (size_t i = 0; i < n; i++) { + zend_get_gc_buffer_add_zval(gc_buffer, &zvs[i]); + } +} + static void zend_get_gc_buffer_release() { zend_get_gc_buffer *gc_buffer = &EG(get_gc_buffer); efree(gc_buffer->start); diff --git a/Zend/zend_gc.h b/Zend/zend_gc.h index 3221335733e..0008b07845b 100644 --- a/Zend/zend_gc.h +++ b/Zend/zend_gc.h @@ -93,6 +93,7 @@ typedef struct { ZEND_API zend_get_gc_buffer *zend_get_gc_buffer_create(void); ZEND_API void zend_get_gc_buffer_grow(zend_get_gc_buffer *gc_buffer); +ZEND_API void zend_get_gc_buffer_add_zvals(zend_get_gc_buffer *gc_buffer, zval *zvs, size_t n); static zend_always_inline void zend_get_gc_buffer_add_zval( zend_get_gc_buffer *gc_buffer, zval *zv) { @@ -114,6 +115,15 @@ static zend_always_inline void zend_get_gc_buffer_add_obj( gc_buffer->cur++; } +static zend_always_inline void zend_get_gc_buffer_add_ht( + zend_get_gc_buffer *gc_buffer, HashTable *ht) { + if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) { + zend_get_gc_buffer_grow(gc_buffer); + } + ZVAL_ARR(gc_buffer->cur, ht); + gc_buffer->cur++; +} + static zend_always_inline void zend_get_gc_buffer_use( zend_get_gc_buffer *gc_buffer, zval **table, int *n) { *table = gc_buffer->start; diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index ed464cf8281..b63e4f71176 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -2079,10 +2079,6 @@ static void spl_dual_it_dtor(zend_object *_object) zend_objects_destroy_object(_object); spl_dual_it_free(object); - - if (object->inner.iterator) { - zend_iterator_dtor(object->inner.iterator); - } } /* }}} */ @@ -2091,6 +2087,9 @@ static void spl_dual_it_free_storage(zend_object *_object) { spl_dual_it_object *object = spl_dual_it_from_obj(_object); + if (object->inner.iterator) { + zend_iterator_dtor(object->inner.iterator); + } if (!Z_ISUNDEF(object->inner.zobject)) { zval_ptr_dtor(&object->inner.zobject); @@ -2137,6 +2136,17 @@ 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 (object->inner.iterator && object->inner.iterator->funcs->get_gc) { + zval *inner_table; + int inner_n; + HashTable *inner_ht = object->inner.iterator->funcs->get_gc( + object->inner.iterator, &inner_table, &inner_n); + zend_get_gc_buffer_add_zvals(gc_buffer, inner_table, inner_n); + if (inner_ht) { + zend_get_gc_buffer_add_ht(gc_buffer, inner_ht); + } + } + if (!Z_ISUNDEF(object->inner.zobject)) { zend_get_gc_buffer_add_zval(gc_buffer, &object->inner.zobject); }