diff options
author | Nikita Popov <nikic@php.net> | 2012-06-23 16:08:15 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2012-06-23 16:08:15 +0200 |
commit | ab75ed6ba9b5eace710976bf76d631728d4bb403 (patch) | |
tree | ac7d081bb197d1d7cd09475a9f74ec8cbeb9c369 | |
parent | 14766e1417c721d9643f6a2a785db3e88b565814 (diff) | |
download | php-git-ab75ed6ba9b5eace710976bf76d631728d4bb403.tar.gz |
Disallow closing a generator during its execution
If a generator is closed while it is running an E_WARNING is thrown and the
call is ignored. Maybe a fatal error should be thrown instead?
-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; |