]> granicus.if.org Git - php/commitdiff
Fix crash when last yielded value is a closure
authorNikita Popov <nikic@php.net>
Fri, 21 Dec 2012 16:28:20 +0000 (17:28 +0100)
committerNikita Popov <nikic@php.net>
Fri, 21 Dec 2012 16:28:20 +0000 (17:28 +0100)
If zend_generator_close is called from within zend_generator_resume (e.g.
due to a return statement) then all the EGs will still be using the values
from the generator. That's why the stack frame has to be the last thing
that is dtored, otherwise some other dtor that is using
EG(current_execute_data) might access the already freed memory segment.
This was the case with the closure dtor.

The fix is to move the dtors for key and value to the start of the handler.
This way the stack frame is the last thing that is freed.

Zend/tests/generators/yield_closure.phpt [new file with mode: 0644]
Zend/zend_generators.c

diff --git a/Zend/tests/generators/yield_closure.phpt b/Zend/tests/generators/yield_closure.phpt
new file mode 100644 (file)
index 0000000..e380b29
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Generator shouldn't crash if last yielded value is a closure
+--FILE--
+<?php
+
+function gen() {
+    yield function() {};
+}
+
+$gen = gen();
+$gen->next();
+
+echo "Done!";
+
+?>
+--EXPECT--
+Done!
index a1917416ef9d92856f84ae3c8640a9b1503dc213..b16687c3d85edf0d7c1094f7f11f5af3d9bcb0b6 100644 (file)
@@ -29,6 +29,16 @@ static zend_object_handlers zend_generator_handlers;
 
 ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution TSRMLS_DC) /* {{{ */
 {
+       if (generator->value) {
+               zval_ptr_dtor(&generator->value);
+               generator->value = NULL;
+       }
+
+       if (generator->key) {
+               zval_ptr_dtor(&generator->key);
+               generator->key = NULL;
+       }
+
        if (generator->execute_data) {
                zend_execute_data *execute_data = generator->execute_data;
                zend_op_array *op_array = execute_data->op_array;
@@ -162,16 +172,6 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
                }
                generator->execute_data = NULL;
        }
-
-       if (generator->value) {
-               zval_ptr_dtor(&generator->value);
-               generator->value = NULL;
-       }
-
-       if (generator->key) {
-               zval_ptr_dtor(&generator->key);
-               generator->key = NULL;
-       }
 }
 /* }}} */