]> granicus.if.org Git - php/commitdiff
Fix segfault when traversing a by-ref generator twice
authorNikita Popov <nikic@php.net>
Wed, 29 Aug 2012 18:46:56 +0000 (20:46 +0200)
committerNikita Popov <nikic@php.net>
Wed, 29 Aug 2012 18:46:56 +0000 (20:46 +0200)
If you try to traverse an already closed generator an exception will now be
thrown.

Furthermore this changes the error for traversing a by-val generator by-ref
from an E_ERROR to an Exception.

Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt
Zend/tests/generators/generator_rewind.phpt
Zend/zend_generators.c

index 9c618d25156125a470836813da3060158a7724eb..de5b22f6ba63ec4712e0215ae33c75405b78991b 100644 (file)
@@ -10,4 +10,9 @@ foreach ($gen as &$value) { }
 
 ?>
 --EXPECTF--
-Fatal error: You can only iterate a generator by-reference if it declared that it yields by-reference in %s on line %d
+Fatal error: Uncaught exception 'Exception' with message 'You can only iterate a generator by-reference if it declared that it yields by-reference' in %s:%d
+Stack trace:
+#0 %s(%d): unknown()
+#1 {main}
+  thrown in %s on line %d
+
index af885ef38203d6304eb70a6a87ad8edcc570bc34..c4b5bbbdf494497b84d329205b8e6ff1ae69dad0 100644 (file)
@@ -21,21 +21,27 @@ try {
     echo "\n", $e, "\n\n";
 }
 
-$gen = gen();
+function &gen2() {
+    $foo = 'bar';
+    yield $foo;
+    yield $foo;
+}
+
+$gen = gen2();
 foreach ($gen as $v) { }
 try {
     foreach ($gen as $v) { }
 } catch (Exception $e) {
-    echo "\n", $e, "\n\n";
+    echo $e, "\n\n";
 }
 
-function gen2() {
+function gen3() {
     echo "in generator\n";
 
     if (false) yield;
 }
 
-$gen = gen2();
+$gen = gen3();
 $gen->rewind();
 
 ?>
@@ -48,10 +54,7 @@ Stack trace:
 #0 %s(%d): Generator->rewind()
 #1 {main}
 
-before yield
-after yield
-
-exception 'Exception' with message 'Cannot rewind a generator that was already run' in %s:%d
+exception 'Exception' with message 'Cannot traverse an already closed generator' in %s:%d
 Stack trace:
 #0 %s(%d): unknown()
 #1 {main}
index 0eb17d02937bb2537b04014224bfa1ac5a555122..60fa8b64911fdb3463da60ca26827be4b6c2423a 100644 (file)
@@ -766,8 +766,14 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob
 
        generator = (zend_generator *) zend_object_store_get_object(object TSRMLS_CC);
 
+       if (!generator->execute_data) {
+               zend_throw_exception(NULL, "Cannot traverse an already closed generator", 0 TSRMLS_CC);
+               return NULL;
+       }
+
        if (by_ref && !(generator->execute_data->op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
-               zend_error(E_ERROR, "You can only iterate a generator by-reference if it declared that it yields by-reference");
+               zend_throw_exception(NULL, "You can only iterate a generator by-reference if it declared that it yields by-reference", 0 TSRMLS_CC);
+               return NULL;
        }
 
        iterator = emalloc(sizeof(zend_generator_iterator));