Skip to content

Commit

Permalink
- Fixed bug #61418 (Segmentation fault when DirectoryIterator's or
Browse files Browse the repository at this point in the history
  FilesystemIterator's iterators are requested more than once without
  having had its dtor callback called in between).
  • Loading branch information
cataphract committed Mar 18, 2012
1 parent e132db7 commit a369972
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 15 deletions.
47 changes: 32 additions & 15 deletions ext/spl/spl_directory.c
Expand Up @@ -120,6 +120,16 @@ static void spl_filesystem_object_free_storage(void *object TSRMLS_DC) /* {{{ */
spl_filesystem_file_free_line(intern TSRMLS_CC);
break;
}

{
zend_object_iterator *iterator;
iterator = (zend_object_iterator*)
spl_filesystem_object_to_iterator(intern);
if (iterator->data != NULL) {
iterator->data = NULL;
iterator->funcs->dtor(iterator TSRMLS_CC);
}
}
efree(object);
} /* }}} */

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

Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
iterator->intern.data = (void*)object;
iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
iterator->current = object;
/* initialize iterator if it wasn't gotten before */
if (iterator->intern.data == NULL) {
iterator->intern.data = object;
iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
/* ->current must be initialized; rewind doesn't set it and valid
* doesn't check whether it's set */
iterator->current = object;
}
zval_add_ref(&object);

return (zend_object_iterator*)iterator;
}
Expand Down Expand Up @@ -1720,15 +1735,15 @@ static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC)
static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter TSRMLS_DC)
{
spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
zval *zfree = (zval*)iterator->intern.data;

if (iterator->current) {
zval_ptr_dtor(&iterator->current);
if (iterator->intern.data) {
zval *object = iterator->intern.data;
zval_ptr_dtor(&object);
} else {
if (iterator->current) {
zval_ptr_dtor(&iterator->current);
}
}
iterator->intern.data = NULL; /* mark as unused */
/* free twice as we add ref twice */
zval_ptr_dtor(&zfree);
zval_ptr_dtor(&zfree);
}
/* }}} */

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

Z_SET_REFCOUNT_P(object, Z_REFCOUNT_P(object) + 2);
iterator->intern.data = (void*)object;
iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
iterator->current = NULL;
/* initialize iterator if wasn't gotten before */
if (iterator->intern.data == NULL) {
iterator->intern.data = object;
iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
}
zval_add_ref(&object);

return (zend_object_iterator*)iterator;
}
Expand Down
23 changes: 23 additions & 0 deletions ext/spl/tests/bug61418.phpt
@@ -0,0 +1,23 @@
--TEST--
Bug #61418: Segmentation fault using FiltesystemIterator & RegexIterator
--FILE--
<?php
$fileIterator = new FilesystemIterator(__DIR__, FilesystemIterator::KEY_AS_FILENAME);
$regexpIterator = new RegexIterator($fileIterator, '#.*#');
foreach ($fileIterator as $key => $file)
{
}
unset($regexpIterator);
unset($fileIterator);

$dirIterator = new DirectoryIterator(__DIR__);
$regexpIterator2 = new RegexIterator($dirIterator, '#.*#');
foreach ($dirIterator as $key => $file)
{
}
unset($regexpIterator2);
unset($dirIterator);
?>
==DONE==
--EXPECT--
==DONE==

0 comments on commit a369972

Please sign in to comment.