summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2012-06-23 16:08:15 +0200
committerNikita Popov <nikic@php.net>2012-06-23 16:08:15 +0200
commitab75ed6ba9b5eace710976bf76d631728d4bb403 (patch)
treeac7d081bb197d1d7cd09475a9f74ec8cbeb9c369
parent14766e1417c721d9643f6a2a785db3e88b565814 (diff)
downloadphp-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.c13
-rw-r--r--Zend/zend_generators.h4
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;