diff options
-rw-r--r-- | Zend/zend_generators.c | 13 | ||||
-rw-r--r-- | Zend/zend_generators.h | 4 |
2 files changed, 17 insertions, 0 deletions
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 487975e23e..bccbb48ca4 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -300,6 +300,8 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM /* The key will be incremented on first use, so it'll start at 0 */ generator->largest_used_integer_key = -1; + generator->is_currently_running = 0; + zend_object_std_init(&generator->std, class_type TSRMLS_CC); object.handle = zend_objects_store_put(generator, NULL, @@ -339,6 +341,8 @@ static void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */ zend_class_entry *original_scope = EG(scope); zend_class_entry *original_called_scope = EG(called_scope); + zend_bool original_is_currently_running = generator->is_currently_running; + /* Remember the current stack position so we can back up pushed args */ generator->original_stack_top = zend_vm_stack_top(TSRMLS_C); @@ -363,6 +367,8 @@ static void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */ EG(scope) = generator->execute_data->current_scope; EG(called_scope) = generator->execute_data->current_called_scope; + generator->is_currently_running = 1; + /* We want the backtrace to look as if the generator function was * called from whatever method we are current running (e.g. next()). * The first prev_execute_data contains an additional stack frame, @@ -387,6 +393,8 @@ static void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */ EG(scope) = original_scope; EG(called_scope) = original_called_scope; + generator->is_currently_running = original_is_currently_running; + /* The stack top before and after the execution differ, i.e. there are * arguments pushed to the stack. */ if (generator->original_stack_top != zend_vm_stack_top(TSRMLS_C)) { @@ -549,6 +557,11 @@ ZEND_METHOD(Generator, close) generator = (zend_generator *) zend_object_store_get_object(getThis() TSRMLS_CC); + if (generator->is_currently_running) { + zend_error(E_WARNING, "A generator cannot be closed while it is running"); + return; + } + zend_generator_close(generator, 0 TSRMLS_CC); } /* }}} */ diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index 89193bbe6e..73d85287a7 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -46,6 +46,10 @@ typedef struct _zend_generator { temp_variable *send_target; /* Largest used integer key for auto-incrementing keys */ long largest_used_integer_key; + + /* We need to know whether the generator is currently executed to avoid it + * being closed while still running */ + zend_bool is_currently_running; } zend_generator; extern ZEND_API zend_class_entry *zend_ce_generator; |