diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 33b35dc6bca9b..e0fe1292569bb 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2053,6 +2053,12 @@ PHP_METHOD(SplFileObject, __construct) RETURN_THROWS(); } + /* Prevent reinitialization of Object */ + if (UNEXPECTED(intern->u.file.stream)) { + zend_throw_error(NULL, "Cannot call constructor twice"); + RETURN_THROWS(); + } + intern->u.file.open_mode = zend_string_copy(open_mode); /* file_name and zcontext are copied by spl_filesystem_file_open() */ intern->file_name = file_name; @@ -2096,7 +2102,7 @@ PHP_METHOD(SplTempFileObject, __construct) } /* Prevent reinitialization of Object */ - if (intern->u.file.stream) { + if (UNEXPECTED(intern->u.file.stream)) { zend_throw_error(NULL, "Cannot call constructor twice"); RETURN_THROWS(); } diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 976d29283b965..c7081f736d32c 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -538,6 +538,20 @@ static int spl_get_iterator_from_aggregate(zval *retval, zend_class_entry *ce, z return SUCCESS; } +static void spl_RecursiveIteratorIterator_free_iterators(spl_recursive_it_object *object) +{ + if (object->iterators) { + while (object->level >= 0) { + zend_object_iterator *sub_iter = object->iterators[object->level].iterator; + zend_iterator_dtor(sub_iter); + zval_ptr_dtor(&object->iterators[object->level].zobject); + object->level--; + } + efree(object->iterators); + object->iterators = NULL; + } +} + static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type) { zval *object = ZEND_THIS; @@ -604,6 +618,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla } intern = Z_SPLRECURSIVE_IT_P(object); + spl_RecursiveIteratorIterator_free_iterators(intern); intern->iterators = emalloc(sizeof(spl_sub_iterator)); intern->level = 0; intern->mode = mode; @@ -650,6 +665,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla intern->iterators[0].getchildren = NULL; if (EG(exception)) { + // TODO: use spl_RecursiveIteratorIterator_free_iterators zend_object_iterator *sub_iter; while (intern->level >= 0) { @@ -958,16 +974,7 @@ static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object) { spl_recursive_it_object *object = spl_recursive_it_from_obj(_object); - if (object->iterators) { - while (object->level >= 0) { - zend_object_iterator *sub_iter = object->iterators[object->level].iterator; - zend_iterator_dtor(sub_iter); - zval_ptr_dtor(&object->iterators[object->level].zobject); - object->level--; - } - efree(object->iterators); - object->iterators = NULL; - } + spl_RecursiveIteratorIterator_free_iterators(object); zend_object_std_dtor(&object->std); for (size_t i = 0; i < 6; i++) { diff --git a/ext/spl/tests/gh16604_1.phpt b/ext/spl/tests/gh16604_1.phpt new file mode 100644 index 0000000000000..3eb2ca9211eaf --- /dev/null +++ b/ext/spl/tests/gh16604_1.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-16604 (Memory leaks in SPL constructors) - recursive iterators +--FILE-- +__construct( $traversable ); + +$obj = new RecursiveTreeIterator( $traversable ); +$obj->__construct( $traversable ); + +?> +--EXPECT-- diff --git a/ext/spl/tests/gh16604_2.phpt b/ext/spl/tests/gh16604_2.phpt new file mode 100644 index 0000000000000..703b37ce87df7 --- /dev/null +++ b/ext/spl/tests/gh16604_2.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-16604 (Memory leaks in SPL constructors) - SplFileObject +--FILE-- +__construct(__DIR__.'/gh16604_2.tmp'); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--CLEAN-- + +--EXPECT-- +Cannot call constructor twice