Skip to content

Commit 714f1ff

Browse files
committed
- Fixed bug #61418 (Segmentation fault when DirectoryIterator's or
FilesystemIterator's iterators are requested more than once without having had its dtor callback called in between).
1 parent ef19fba commit 714f1ff

File tree

3 files changed

+58
-15
lines changed

3 files changed

+58
-15
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ PHP NEWS
8181

8282
- SPL
8383
. Fixed memory leak when calling SplFileInfo's constructor twice. (Felipe)
84+
. Fixed bug #61418 (Segmentation fault when DirectoryIterator's or
85+
FilesystemIterator's iterators are requested more than once without
86+
having had its dtor callback called in between). (Gustavo)
8487
. Fixed bug #61347 (inconsistent isset behavior of Arrayobject). (Laruence)
8588
. Fixed bug #61326 (ArrayObject comparison). (Gustavo)
8689

ext/spl/spl_directory.c

+32-15
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,16 @@ static void spl_filesystem_object_free_storage(void *object TSRMLS_DC) /* {{{ */
120120
spl_filesystem_file_free_line(intern TSRMLS_CC);
121121
break;
122122
}
123+
124+
{
125+
zend_object_iterator *iterator;
126+
iterator = (zend_object_iterator*)
127+
spl_filesystem_object_to_iterator(intern);
128+
if (iterator->data != NULL) {
129+
iterator->data = NULL;
130+
iterator->funcs->dtor(iterator TSRMLS_CC);
131+
}
132+
}
123133
efree(object);
124134
} /* }}} */
125135

@@ -1627,10 +1637,15 @@ zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval
16271637
dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
16281638
iterator = spl_filesystem_object_to_iterator(dir_object);
16291639

1630-
Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
1631-
iterator->intern.data = (void*)object;
1632-
iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
1633-
iterator->current = object;
1640+
/* initialize iterator if it wasn't gotten before */
1641+
if (iterator->intern.data == NULL) {
1642+
iterator->intern.data = object;
1643+
iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
1644+
/* ->current must be initialized; rewind doesn't set it and valid
1645+
* doesn't check whether it's set */
1646+
iterator->current = object;
1647+
}
1648+
zval_add_ref(&object);
16341649

16351650
return (zend_object_iterator*)iterator;
16361651
}
@@ -1709,15 +1724,15 @@ static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC)
17091724
static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter TSRMLS_DC)
17101725
{
17111726
spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1712-
zval *zfree = (zval*)iterator->intern.data;
17131727

1714-
if (iterator->current) {
1715-
zval_ptr_dtor(&iterator->current);
1728+
if (iterator->intern.data) {
1729+
zval *object = iterator->intern.data;
1730+
zval_ptr_dtor(&object);
1731+
} else {
1732+
if (iterator->current) {
1733+
zval_ptr_dtor(&iterator->current);
1734+
}
17161735
}
1717-
iterator->intern.data = NULL; /* mark as unused */
1718-
/* free twice as we add ref twice */
1719-
zval_ptr_dtor(&zfree);
1720-
zval_ptr_dtor(&zfree);
17211736
}
17221737
/* }}} */
17231738

@@ -1828,10 +1843,12 @@ zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zva
18281843
dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
18291844
iterator = spl_filesystem_object_to_iterator(dir_object);
18301845

1831-
Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
1832-
iterator->intern.data = (void*)object;
1833-
iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
1834-
iterator->current = NULL;
1846+
/* initialize iterator if wasn't gotten before */
1847+
if (iterator->intern.data == NULL) {
1848+
iterator->intern.data = object;
1849+
iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
1850+
}
1851+
zval_add_ref(&object);
18351852

18361853
return (zend_object_iterator*)iterator;
18371854
}

ext/spl/tests/bug61418.phpt

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Bug #61418: Segmentation fault using FiltesystemIterator & RegexIterator
3+
--FILE--
4+
<?php
5+
$fileIterator = new FilesystemIterator(__DIR__, FilesystemIterator::KEY_AS_FILENAME);
6+
$regexpIterator = new RegexIterator($fileIterator, '#.*#');
7+
foreach ($fileIterator as $key => $file)
8+
{
9+
}
10+
unset($regexpIterator);
11+
unset($fileIterator);
12+
13+
$dirIterator = new DirectoryIterator(__DIR__);
14+
$regexpIterator2 = new RegexIterator($dirIterator, '#.*#');
15+
foreach ($dirIterator as $key => $file)
16+
{
17+
}
18+
unset($regexpIterator2);
19+
unset($dirIterator);
20+
?>
21+
==DONE==
22+
--EXPECT--
23+
==DONE==

0 commit comments

Comments
 (0)