Skip to content

Commit eaa2b61

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Fix GH-16604: Memory leaks in SPL constructors
2 parents 3cc43bf + 886a528 commit eaa2b61

File tree

5 files changed

+61
-11
lines changed

5 files changed

+61
-11
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ PHP NEWS
120120
. Fixed bug GH-16589 (UAF in SplDoublyLinked->serialize()). (nielsdos)
121121
. Fixed bug GH-14687 (segfault on SplObjectIterator instance).
122122
(David Carlier)
123+
. Fixed bug GH-16604 (Memory leaks in SPL constructors). (nielsdos)
123124

124125
- Standard:
125126
. Fixed bug GH-16293 (Failed assertion when throwing in assert() callback with

ext/spl/spl_directory.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2046,6 +2046,12 @@ PHP_METHOD(SplFileObject, __construct)
20462046
RETURN_THROWS();
20472047
}
20482048

2049+
/* Prevent reinitialization of Object */
2050+
if (UNEXPECTED(intern->u.file.stream)) {
2051+
zend_throw_error(NULL, "Cannot call constructor twice");
2052+
RETURN_THROWS();
2053+
}
2054+
20492055
intern->u.file.open_mode = zend_string_copy(open_mode);
20502056
/* file_name and zcontext are copied by spl_filesystem_file_open() */
20512057
intern->file_name = file_name;
@@ -2089,7 +2095,7 @@ PHP_METHOD(SplTempFileObject, __construct)
20892095
}
20902096

20912097
/* Prevent reinitialization of Object */
2092-
if (intern->u.file.stream) {
2098+
if (UNEXPECTED(intern->u.file.stream)) {
20932099
zend_throw_error(NULL, "Cannot call constructor twice");
20942100
RETURN_THROWS();
20952101
}

ext/spl/spl_iterators.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,20 @@ static zend_result spl_get_iterator_from_aggregate(zval *retval, zend_class_entr
532532
return SUCCESS;
533533
}
534534

535+
static void spl_RecursiveIteratorIterator_free_iterators(spl_recursive_it_object *object)
536+
{
537+
if (object->iterators) {
538+
while (object->level >= 0) {
539+
zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
540+
zend_iterator_dtor(sub_iter);
541+
zval_ptr_dtor(&object->iterators[object->level].zobject);
542+
object->level--;
543+
}
544+
efree(object->iterators);
545+
object->iterators = NULL;
546+
}
547+
}
548+
535549
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)
536550
{
537551
zval *object = ZEND_THIS;
@@ -598,6 +612,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
598612
}
599613

600614
intern = Z_SPLRECURSIVE_IT_P(object);
615+
spl_RecursiveIteratorIterator_free_iterators(intern);
601616
intern->iterators = emalloc(sizeof(spl_sub_iterator));
602617
intern->level = 0;
603618
intern->mode = mode;
@@ -644,6 +659,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
644659
intern->iterators[0].getchildren = NULL;
645660

646661
if (EG(exception)) {
662+
// TODO: use spl_RecursiveIteratorIterator_free_iterators
647663
zend_object_iterator *sub_iter;
648664

649665
while (intern->level >= 0) {
@@ -952,16 +968,7 @@ static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object)
952968
{
953969
spl_recursive_it_object *object = spl_recursive_it_from_obj(_object);
954970

955-
if (object->iterators) {
956-
while (object->level >= 0) {
957-
zend_object_iterator *sub_iter = object->iterators[object->level].iterator;
958-
zend_iterator_dtor(sub_iter);
959-
zval_ptr_dtor(&object->iterators[object->level].zobject);
960-
object->level--;
961-
}
962-
efree(object->iterators);
963-
object->iterators = NULL;
964-
}
971+
spl_RecursiveIteratorIterator_free_iterators(object);
965972

966973
zend_object_std_dtor(&object->std);
967974
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)