summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--py/objgenerator.c10
-rw-r--r--tests/basics/gen_yield_from_executing.py15
-rwxr-xr-xtests/run-tests2
3 files changed, 26 insertions, 1 deletions
diff --git a/py/objgenerator.c b/py/objgenerator.c
index d500dbd9d..a2ad490d6 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -117,9 +117,19 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
*self->code_state.sp = send_value;
}
}
+
+ // We set self->globals=NULL while executing, for a sentinel to ensure the generator
+ // cannot be reentered during execution
+ if (self->globals == NULL) {
+ mp_raise_ValueError("generator already executing");
+ }
+
+ // Set up the correct globals context for the generator and execute it
self->code_state.old_globals = mp_globals_get();
mp_globals_set(self->globals);
+ self->globals = NULL;
mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value);
+ self->globals = mp_globals_get();
mp_globals_set(self->code_state.old_globals);
switch (ret_kind) {
diff --git a/tests/basics/gen_yield_from_executing.py b/tests/basics/gen_yield_from_executing.py
new file mode 100644
index 000000000..cad0c7695
--- /dev/null
+++ b/tests/basics/gen_yield_from_executing.py
@@ -0,0 +1,15 @@
+# yielding from an already executing generator is not allowed
+
+def f():
+ yield 1
+ # g here is already executing so this will raise an exception
+ yield from g
+
+g = f()
+
+print(next(g))
+
+try:
+ next(g)
+except ValueError:
+ print('ValueError')
diff --git a/tests/run-tests b/tests/run-tests
index afefa264f..25fb33a3f 100755
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -336,7 +336,7 @@ def run_tests(pyb, tests, args, base_path="."):
# Some tests are known to fail with native emitter
# Remove them from the below when they work
if args.emit == 'native':
- skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield
+ skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_executing gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield
skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join'.split()}) # require yield
skip_tests.update({'basics/async_%s.py' % t for t in 'def await await2 for for2 with with2'.split()}) # require yield
skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs