From 14f133036cfa6c2ab3f5eb9af3a0c0b29ed5d554 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 21 Dec 2012 17:28:20 +0100 Subject: [PATCH] Fix crash when last yielded value is a closure 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 | 17 +++++++++++++++++ Zend/zend_generators.c | 20 ++++++++++---------- 2 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 Zend/tests/generators/yield_closure.phpt diff --git a/Zend/tests/generators/yield_closure.phpt b/Zend/tests/generators/yield_closure.phpt new file mode 100644 index 0000000000..e380b29946 --- /dev/null +++ b/Zend/tests/generators/yield_closure.phpt @@ -0,0 +1,17 @@ +--TEST-- +Generator shouldn't crash if last yielded value is a closure +--FILE-- +next(); + +echo "Done!"; + +?> +--EXPECT-- +Done! diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index a1917416ef..b16687c3d8 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -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; - } } /* }}} */ -- 2.40.0