Skip to content

Commit 2b17168

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix GH-16604: Memory leaks in SPL constructors
2 parents 063de1f + 7a78ffc commit 2b17168

File tree

4 files changed

+60
-11
lines changed

4 files changed

+60
-11
lines changed

ext/spl/spl_directory.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2027,6 +2027,12 @@ PHP_METHOD(SplFileObject, __construct)
20272027
RETURN_THROWS();
20282028
}
20292029

2030+
/* Prevent reinitialization of Object */
2031+
if (UNEXPECTED(intern->u.file.stream)) {
2032+
zend_throw_error(NULL, "Cannot call constructor twice");
2033+
RETURN_THROWS();
2034+
}
2035+
20302036
intern->u.file.open_mode = zend_string_copy(open_mode);
20312037
/* file_name and zcontext are copied by spl_filesystem_file_open() */
20322038
intern->file_name = file_name;
@@ -2070,7 +2076,7 @@ PHP_METHOD(SplTempFileObject, __construct)
20702076
}
20712077

20722078
/* Prevent reinitialization of Object */
2073-
if (intern->u.file.stream) {
2079+
if (UNEXPECTED(intern->u.file.stream)) {
20742080
zend_throw_error(NULL, "Cannot call constructor twice");
20752081
RETURN_THROWS();
20762082
}

ext/spl/spl_iterators.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,20 @@ static zend_result spl_get_iterator_from_aggregate(zval *retval, zend_class_entr
524524
return SUCCESS;
525525
}
526526

527+
static void spl_RecursiveIteratorIterator_free_iterators(spl_recursive_it_object *object)
528+
{
529+
if (object->iterators) {
530+
while (object->level >= 0) {
531+
zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
532+
zend_iterator_dtor(sub_iter);
533+
zval_ptr_dtor(&object->iterators[object->level].zobject);
534+
object->level--;
535+
}
536+
efree(object->iterators);
537+
object->iterators = NULL;
538+
}
539+
}
540+
527541
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)
528542
{
529543
zval *object = ZEND_THIS;
@@ -594,6 +608,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
594608
}
595609

596610
intern = Z_SPLRECURSIVE_IT_P(object);
611+
spl_RecursiveIteratorIterator_free_iterators(intern);
597612
intern->iterators = emalloc(sizeof(spl_sub_iterator));
598613
intern->level = 0;
599614
intern->mode = mode;
@@ -640,6 +655,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
640655
intern->iterators[0].getchildren = NULL;
641656

642657
if (EG(exception)) {
658+
// TODO: use spl_RecursiveIteratorIterator_free_iterators
643659
zend_object_iterator *sub_iter;
644660

645661
while (intern->level >= 0) {
@@ -912,16 +928,7 @@ static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object)
912928
{
913929
spl_recursive_it_object *object = spl_recursive_it_from_obj(_object);
914930

915-
if (object->iterators) {
916-
while (object->level >= 0) {
917-
zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
918-
zend_iterator_dtor(sub_iter);
919-
zval_ptr_dtor(&object->iterators[object->level].zobject);
920-
object->level--;
921-
}
922-
efree(object->iterators);
923-
object->iterators = NULL;
924-
}
931+
spl_RecursiveIteratorIterator_free_iterators(object);
925932

926933
zend_object_std_dtor(&object->std);
927934
for (size_t i = 0; i < 6; i++) {

ext/spl/tests/gh16604_1.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-16604 (Memory leaks in SPL constructors) - recursive iterators
3+
--FILE--
4+
<?php
5+
6+
$traversable = new RecursiveArrayIterator( [] );
7+
8+
$obj = new RecursiveIteratorIterator( $traversable );
9+
$obj->__construct( $traversable );
10+
11+
$obj = new RecursiveTreeIterator( $traversable );
12+
$obj->__construct( $traversable );
13+
14+
?>
15+
--EXPECT--

ext/spl/tests/gh16604_2.phpt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
GH-16604 (Memory leaks in SPL constructors) - SplFileObject
3+
--FILE--
4+
<?php
5+
6+
file_put_contents(__DIR__.'/gh16604_2.tmp', 'hello');
7+
8+
$obj = new SplFileObject(__DIR__.'/gh16604_2.tmp');
9+
try {
10+
$obj->__construct(__DIR__.'/gh16604_2.tmp');
11+
} catch (Error $e) {
12+
echo $e->getMessage(), "\n";
13+
}
14+
15+
?>
16+
--CLEAN--
17+
<?php
18+
@unlink(__DIR__.'/gh16604_2.tmp');
19+
?>
20+
--EXPECT--
21+
Cannot call constructor twice

0 commit comments

Comments
 (0)