Merge branch 'PHP-8.4'

* PHP-8.4:
  Fix GH-16604: Memory leaks in SPL constructors
This commit is contained in:
Niels Dossche 2024-11-01 20:43:49 +01:00
commit 2b17168ac1
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
4 changed files with 60 additions and 11 deletions

View file

@ -2027,6 +2027,12 @@ PHP_METHOD(SplFileObject, __construct)
RETURN_THROWS(); 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); intern->u.file.open_mode = zend_string_copy(open_mode);
/* file_name and zcontext are copied by spl_filesystem_file_open() */ /* file_name and zcontext are copied by spl_filesystem_file_open() */
intern->file_name = file_name; intern->file_name = file_name;
@ -2070,7 +2076,7 @@ PHP_METHOD(SplTempFileObject, __construct)
} }
/* Prevent reinitialization of Object */ /* Prevent reinitialization of Object */
if (intern->u.file.stream) { if (UNEXPECTED(intern->u.file.stream)) {
zend_throw_error(NULL, "Cannot call constructor twice"); zend_throw_error(NULL, "Cannot call constructor twice");
RETURN_THROWS(); RETURN_THROWS();
} }

View file

@ -524,6 +524,20 @@ static zend_result spl_get_iterator_from_aggregate(zval *retval, zend_class_entr
return SUCCESS; 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) 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; zval *object = ZEND_THIS;
@ -594,6 +608,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
} }
intern = Z_SPLRECURSIVE_IT_P(object); intern = Z_SPLRECURSIVE_IT_P(object);
spl_RecursiveIteratorIterator_free_iterators(intern);
intern->iterators = emalloc(sizeof(spl_sub_iterator)); intern->iterators = emalloc(sizeof(spl_sub_iterator));
intern->level = 0; intern->level = 0;
intern->mode = mode; intern->mode = mode;
@ -640,6 +655,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
intern->iterators[0].getchildren = NULL; intern->iterators[0].getchildren = NULL;
if (EG(exception)) { if (EG(exception)) {
// TODO: use spl_RecursiveIteratorIterator_free_iterators
zend_object_iterator *sub_iter; zend_object_iterator *sub_iter;
while (intern->level >= 0) { while (intern->level >= 0) {
@ -912,16 +928,7 @@ static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object)
{ {
spl_recursive_it_object *object = spl_recursive_it_from_obj(_object); spl_recursive_it_object *object = spl_recursive_it_from_obj(_object);
if (object->iterators) { spl_RecursiveIteratorIterator_free_iterators(object);
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;
}
zend_object_std_dtor(&object->std); zend_object_std_dtor(&object->std);
for (size_t i = 0; i < 6; i++) { for (size_t i = 0; i < 6; i++) {

View file

@ -0,0 +1,15 @@
--TEST--
GH-16604 (Memory leaks in SPL constructors) - recursive iterators
--FILE--
<?php
$traversable = new RecursiveArrayIterator( [] );
$obj = new RecursiveIteratorIterator( $traversable );
$obj->__construct( $traversable );
$obj = new RecursiveTreeIterator( $traversable );
$obj->__construct( $traversable );
?>
--EXPECT--

View file

@ -0,0 +1,21 @@
--TEST--
GH-16604 (Memory leaks in SPL constructors) - SplFileObject
--FILE--
<?php
file_put_contents(__DIR__.'/gh16604_2.tmp', 'hello');
$obj = new SplFileObject(__DIR__.'/gh16604_2.tmp');
try {
$obj->__construct(__DIR__.'/gh16604_2.tmp');
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?>
--CLEAN--
<?php
@unlink(__DIR__.'/gh16604_2.tmp');
?>
--EXPECT--
Cannot call constructor twice