php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71436 Segfault in AppendIterator with empty generator
Submitted: 2016-01-23 22:43 UTC Modified: 2021-04-23 16:30 UTC
Votes:12
Avg. Score:4.1 ± 1.1
Reproduced:10 of 11 (90.9%)
Same Version:4 (40.0%)
Same OS:2 (20.0%)
From: matej21 at matej21 dot cz Assigned: nikic (profile)
Status: Duplicate Package: SPL related
PHP Version: 7.0.2 OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: matej21 at matej21 dot cz
New email:
PHP Version: OS:

 

 [2016-01-23 22:43 UTC] matej21 at matej21 dot cz
Description:
------------
AppendIterator produces a segfault when it iterates over an empty generator.

https://3v4l.org/q3I67

Test script:
---------------
<?php
function foo() {
        foreach ([] as $foo) {
                yield $foo;
        }
}
$iterator = new AppendIterator();
$iterator->append(foo());
var_dump(iterator_to_array($iterator));


Expected result:
----------------
array(0) {
}

Actual result:
--------------
Program received signal SIGSEGV, Segmentation fault.


#0  spl_dual_it_rewind (intern=0x7fffed2783c0) at /usr/local/src/php/ext/spl/spl_iterators.c:1682
#1  spl_append_it_next_iterator (intern=intern@entry=0x7fffed2783c0) at /usr/local/src/php/ext/spl/spl_iterators.c:3332
#2  0x000000000071fff4 in zim_spl_AppendIterator_rewind (execute_data=<optimized out>, return_value=<optimized out>) at /usr/local/src/php/ext/spl/spl_iterators.c:3403
#3  0x00000000008157df in zend_call_function (fci=fci@entry=0x7fffffffa410, fci_cache=fci_cache@entry=0x7fffffffa3e0) at /usr/local/src/php/Zend/zend_execute_API.c:879
#4  0x000000000083ec54 in zend_call_method (object=object@entry=0x7fffed2691f8, obj_ce=<optimized out>, fn_proxy=0x1287000, function_name=function_name@entry=0x989d4c "rewind", function_name_len=function_name_len@entry=6, 
    retval_ptr=retval_ptr@entry=0x0, param_count=param_count@entry=0, arg1=arg1@entry=0x0, arg2=arg2@entry=0x0) at /usr/local/src/php/Zend/zend_interfaces.c:104
#5  0x000000000083f25a in zend_user_it_rewind (_iter=0x7fffed2691c0) at /usr/local/src/php/Zend/zend_interfaces.c:245
#6  0x0000000000720212 in spl_iterator_apply (obj=<optimized out>, apply_func=0x719ae0 <spl_iterator_to_array_apply>, puser=puser@entry=0x7fffed2130f0) at /usr/local/src/php/ext/spl/spl_iterators.c:3503
#7  0x00000000007202e5 in zif_iterator_to_array (execute_data=<optimized out>, return_value=0x7fffed2130f0) at /usr/local/src/php/ext/spl/spl_iterators.c:3590
#8  0x000000000089c12b in ZEND_DO_FCALL_SPEC_HANDLER () at /usr/local/src/php/Zend/zend_vm_execute.h:842
#9  0x000000000085ed3b in execute_ex (ex=<optimized out>) at /usr/local/src/php/Zend/zend_vm_execute.h:414
#10 0x00000000008a7c27 in zend_execute (op_array=0x7fffed283000, op_array@entry=0x7fffed288180, return_value=return_value@entry=0x7fffed213030) at /usr/local/src/php/Zend/zend_vm_execute.h:458
#11 0x0000000000823494 in zend_execute_scripts (type=type@entry=8, retval=0x7fffed213030, retval@entry=0x0, file_count=file_count@entry=3) at /usr/local/src/php/Zend/zend.c:1427
#12 0x00000000007c7698 in php_execute_script (primary_file=primary_file@entry=0x7fffffffc9c0) at /usr/local/src/php/main/main.c:2484
#13 0x00000000008a97f3 in do_cli (argc=2, argv=0x119cc10) at /usr/local/src/php/sapi/cli/php_cli.c:974
#14 0x000000000044d9e0 in main (argc=2, argv=0x119cc10) at /usr/local/src/php/sapi/cli/php_cli.c:1345


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-01-24 06:47 UTC] laruence@php.net
-Assigned To: +Assigned To: nikic
 [2016-01-24 06:47 UTC] laruence@php.net
with a quick fix (check null pointer) : 
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index c6181d9..bb86e76 100644
--- a/ext/spl/spl_iterators.c
+++ b/ext/spl/spl_iterators.c
@@ -1682,7 +1682,7 @@ static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
 {
 	spl_dual_it_free(intern TSRMLS_CC);
 	intern->current.pos = 0;
-	if (intern->inner.iterator->funcs->rewind) {
+	if (intern->inner.iterator && intern->inner.iterator->funcs->rewind) {
 		intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC);
 	}
 }

will get:
Fatal error: Uncaught exception 'Exception' with message 'Cannot traverse an already closed generator' in /tmp/1.php:9
Stack trace:
#0 [internal function]: AppendIterator->rewind()
#1 /tmp/1.php(9): iterator_to_array(Object(AppendIterator))
#2 {main}
  thrown in /tmp/1.php on line 9


which seems not quite reasonable error message. 

@nikic, what do you think?
 [2016-01-24 10:07 UTC] nikic@php.net
@laruence: There are two bugs here:
a) It does not handle exceptions thrown from get_iterator(). This is what you fixed.
b) It calls get_iterator() multiple times for some reason, which is why there is an exception in the first place.
 [2016-03-09 21:49 UTC] crahobzy at ukr dot net
I experience the same problem with PHP 5.6.19. @nikic are there any chances to fix it?
 [2016-03-24 16:54 UTC] savageman86 at gmail dot com
Same bug on 5.5.9
 [2016-07-28 23:32 UTC] brian dot carpenter at gmail dot com
This crash is present in 5.6.24.
 [2017-03-02 16:08 UTC] tom60 at op dot pl
Possibly related:

-------------------------------------------------------
#0  zend_mm_alloc_small (size=56, bin_num=6, heap=0x7f8c9de00040) at /src/php-7.1.2/Zend/zend_alloc.c:1261
#1  _emalloc_56 () at /src/php-7.1.2/Zend/zend_alloc.c:2336
#2  0x000000000080d7a0 in _array_init (arg=arg@entry=0x7ffffdaf06f0, size=size@entry=0) at /src/php-7.1.2/Zend/zend_API.c:1060
#3  0x0000000000824f31 in zend_fetch_debug_backtrace (return_value=return_value@entry=0x7ffffdaf0780, skip_last=skip_last@entry=0, options=options@entry=0, 
    limit=limit@entry=0) at /src/php-7.1.2/Zend/zend_builtin_functions.c:2612
#4  0x000000000082bb0f in zend_default_exception_new_ex (class_type=0x2015d80, skip_top_traces=0) at /src/php-7.1.2/Zend/zend_exceptions.c:216
#5  0x000000000080df3b in _object_and_properties_init (arg=arg@entry=0x7ffffdaf07f0, class_type=class_type@entry=0x2015d80, properties=properties@entry=0x0)
    at /src/php-7.1.2/Zend/zend_API.c:1302
#6  0x000000000080e047 in _object_init_ex (arg=arg@entry=0x7ffffdaf07f0, class_type=class_type@entry=0x2015d80)
    at /src/php-7.1.2/Zend/zend_API.c:1310
#7  0x0000000000438429 in zend_throw_exception (exception_ce=0x2015d80, exception_ce@entry=0x0, message=message@entry=0xdf6b78 "Cannot traverse an already closed generator", 
    code=code@entry=0) at /src/php-7.1.2/Zend/zend_exceptions.c:922
#8  0x00000000008365ee in zend_generator_get_iterator (ce=<optimized out>, object=0x7f8c9de13980, by_ref=<optimized out>)
    at /src/php-7.1.2/Zend/zend_generators.c:1186
#9  0x00000000006e59c5 in spl_iterator_apply (obj=<optimized out>, apply_func=0x6df320 <spl_iterator_to_values_apply>, puser=puser@entry=0x7f8c9de13920)
    at /src/php-7.1.2/ext/spl/spl_iterators.c:3495
#10 0x00000000006e5af5 in zif_iterator_to_array (execute_data=<optimized out>, return_value=0x7f8c9de13920)
    at /src/php-7.1.2/ext/spl/spl_iterators.c:3590
#11 0x00000000008aa572 in ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER () at /src/php-7.1.2/Zend/zend_vm_execute.h:876
#12 0x000000000085215b in execute_ex (ex=<optimized out>) at /src/php-7.1.2/Zend/zend_vm_execute.h:429
#13 0x0000000000836c32 in zend_generator_resume (orig_generator=0x7f8c9de00040) at /src/php-7.1.2/Zend/zend_generators.c:817
#14 0x00000000008696b9 in ZEND_FE_FETCH_R_SPEC_VAR_HANDLER () at /src/php-7.1.2/Zend/zend_vm_execute.h:16816
#15 0x000000000085215b in execute_ex (ex=<optimized out>) at /src/php-7.1.2/Zend/zend_vm_execute.h:429
#16 0x0000000000836c32 in zend_generator_resume (orig_generator=0x7f8c9de00040) at /src/php-7.1.2/Zend/zend_generators.c:817
#17 0x00000000008696b9 in ZEND_FE_FETCH_R_SPEC_VAR_HANDLER () at /src/php-7.1.2/Zend/zend_vm_execute.h:16816
#18 0x000000000085215b in execute_ex (ex=<optimized out>) at /src/php-7.1.2/Zend/zend_vm_execute.h:429
#19 0x00000000008ad410 in zend_execute (op_array=0x7f8c9de7d000, op_array@entry=0x7f8c9d089d00, return_value=return_value@entry=0x7f8c9de13500)
    at /src/php-7.1.2/Zend/zend_vm_execute.h:474
#20 0x000000000080b834 in zend_execute_scripts (type=type@entry=8, retval=0x7f8c9de13500, retval@entry=0x0, file_count=file_count@entry=3)
    at /src/php-7.1.2/Zend/zend.c:1475
#21 0x00000000007abfb0 in php_execute_script (primary_file=0x7ffffdaf3060) at /src/php-7.1.2/main/main.c:2537
#22 0x00000000008af59a in do_cli (argc=-1646264256, argv=0x0) at /src/php-7.1.2/sapi/cli/php_cli.c:993
#23 0x000000000043a36c in main (argc=-1646264256, argv=0x0) at /src/php-7.1.2/sapi/cli/php_cli.c:1381
 [2017-04-15 20:38 UTC] matej21 at matej21 dot cz
first rewind is invoked by spl_append_it_next_iterator(), second one is invoked by spl_iterator_apply(). 

so maybe some flag telling that append iterator is already rewinded would solve it?
 [2018-04-10 08:08 UTC] sahli at gyselroth dot com
Same here, PHP 7.2.0, AppendIterator is pretty much unusable because of this behaviour.
 [2020-03-25 23:03 UTC] php at seanmorr dot is
You just need to use NoRewindIterator:

<?php
function foo() {
        foreach ([] as $foo) {
                yield $foo;
        }
}
$append = new AppendIterator();
$append->append(new NoRewindIterator(foo()));

var_dump(iterator_to_array($append));
 [2021-04-23 16:30 UTC] cmb@php.net
-Status: Assigned +Status: Duplicate
 [2021-04-23 16:30 UTC] cmb@php.net
The segfault has been already fixed as bug #72684; the other issue
mentioned by Nikita is tracked as bug #72692, so I'm closing this
ticket as duplicate.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sun Jan 05 00:01:29 2025 UTC