Fixed bug #69221
authorNikita Popov <nikic@php.net>
Wed, 11 Mar 2015 17:08:03 +0000 (18:08 +0100)
committerNikita Popov <nikic@php.net>
Fri, 13 Mar 2015 15:23:53 +0000 (16:23 +0100)
A generator iterator can be created from different zvals - use
the object handle to manage references instead.

NEWS
Zend/tests/bug69221.phpt [new file with mode: 0644]
Zend/tests/bug69221_2.phpt [new file with mode: 0644]
Zend/zend_generators.c
Zend/zend_generators.h

diff --git a/NEWS b/NEWS
index 3a431bfad868384c01178b1acecca9fe0cfff9a8..39e404f57749d885745cd9079e111ba0fa8e4261 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,8 @@ PHP                                                                        NEWS
   . Fixed bug #68917 (parse_url fails on some partial urls). (Wei Dai)
   . Fixed bug #69212 (Leaking VIA_HANDLER func when exception thrown in
     __call/... arg passing). (Nikita)
+  . Fixed bug #69221 (Segmentation fault when using a generator in combination
+    with an Iterator). (Nikita)
 
 - Filter:
   . Fixed bug #69202: (FILTER_FLAG_STRIP_BACKTICK ignored unless other
diff --git a/Zend/tests/bug69221.phpt b/Zend/tests/bug69221.phpt
new file mode 100644 (file)
index 0000000..9eb5afc
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Bug #69221: Segmentation fault when using a generator in combination with an Iterator
+--FILE--
+<?php
+
+function gen() {
+       yield 1;
+};
+
+$gen1 = gen();
+$gen2 = (object) $gen1;
+
+foreach ($gen1 as $v1) {
+    foreach ($gen2 as $v2) {
+        break 2;
+    }
+}
+
+unset($gen1);
+foreach ($gen2 as $v) { var_dump($v); }
+
+?>
+--EXPECTF--
+int(1)
diff --git a/Zend/tests/bug69221_2.phpt b/Zend/tests/bug69221_2.phpt
new file mode 100644 (file)
index 0000000..f3805b8
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #69221: Segmentation fault when using a generator in combination with an Iterator (2)
+--FILE--
+<?php
+
+$gen = function() {
+    yield 1;
+};
+
+$iter = new IteratorIterator($gen());
+$ngen = $iter->getInnerIterator();
+
+var_dump(iterator_to_array($ngen, false));
+
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  int(1)
+}
index c96d1e979b9fecc20a17846dd1c5124122d7ed6e..b457f56463ccd4fc17db08fe0a8872d50b5c6a5f 100644 (file)
@@ -605,9 +605,9 @@ ZEND_METHOD(Generator, __wakeup)
 
 static void zend_generator_iterator_dtor(zend_object_iterator *iterator TSRMLS_DC) /* {{{ */
 {
-       zval *object = ((zend_generator_iterator *) iterator)->object;
+       zend_generator_iterator *iter = (zend_generator_iterator *) iterator;
 
-       zval_ptr_dtor(&object);
+       zend_objects_store_del_ref_by_handle(iter->handle TSRMLS_CC);
 }
 /* }}} */
 
@@ -699,8 +699,8 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob
 
        /* We have to keep a reference to the generator object zval around,
         * otherwise the generator may be destroyed during iteration. */
-       Z_ADDREF_P(object);
-       iterator->object = object;
+       iterator->handle = Z_OBJ_HANDLE_P(object);
+       zend_objects_store_add_ref_by_handle(iterator->handle TSRMLS_CC);
 
        return (zend_object_iterator *) iterator;
 }
index d460c908ad1c43eee82eca92d0fc2b3a1602fb26..061ea518cddf4617901d561a45564950f3454006 100644 (file)
@@ -28,9 +28,9 @@ extern ZEND_API zend_class_entry *zend_ce_generator;
 typedef struct _zend_generator_iterator {
        zend_object_iterator intern;
 
-       /* The generator object zval has to be stored, because the iterator is
-        * holding a ref to it, which has to be dtored. */
-       zval *object;
+       /* The generator object handle has to be stored, because the
+        * iterator is holding a ref to it, which has to be dtored. */
+       zend_object_handle handle;
 } zend_generator_iterator;
 
 typedef struct _zend_generator {