Skip to content

Commit a369972

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 e132db7 commit a369972

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

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

@@ -1638,10 +1648,15 @@ zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval
16381648
dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
16391649
iterator = spl_filesystem_object_to_iterator(dir_object);
16401650

1641-
Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
1642-
iterator->intern.data = (void*)object;
1643-
iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
1644-
iterator->current = object;
1651+
/* initialize iterator if it wasn't gotten before */
1652+
if (iterator->intern.data == NULL) {
1653+
iterator->intern.data = object;
1654+
iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
1655+
/* ->current must be initialized; rewind doesn't set it and valid
1656+
* doesn't check whether it's set */
1657+
iterator->current = object;
1658+
}
1659+
zval_add_ref(&object);
16451660

16461661
return (zend_object_iterator*)iterator;
16471662
}
@@ -1720,15 +1735,15 @@ static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC)
17201735
static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter TSRMLS_DC)
17211736
{
17221737
spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1723-
zval *zfree = (zval*)iterator->intern.data;
17241738

1725-
if (iterator->current) {
1726-
zval_ptr_dtor(&iterator->current);
1739+
if (iterator->intern.data) {
1740+
zval *object = iterator->intern.data;
1741+
zval_ptr_dtor(&object);
1742+
} else {
1743+
if (iterator->current) {
1744+
zval_ptr_dtor(&iterator->current);
1745+
}
17271746
}
1728-
iterator->intern.data = NULL; /* mark as unused */
1729-
/* free twice as we add ref twice */
1730-
zval_ptr_dtor(&zfree);
1731-
zval_ptr_dtor(&zfree);
17321747
}
17331748
/* }}} */
17341749

@@ -1839,10 +1854,12 @@ zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zva
18391854
dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
18401855
iterator = spl_filesystem_object_to_iterator(dir_object);
18411856

1842-
Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
1843-
iterator->intern.data = (void*)object;
1844-
iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
1845-
iterator->current = NULL;
1857+
/* initialize iterator if wasn't gotten before */
1858+
if (iterator->intern.data == NULL) {
1859+
iterator->intern.data = object;
1860+
iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
1861+
}
1862+
zval_add_ref(&object);
18461863

18471864
return (zend_object_iterator*)iterator;
18481865
}

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)