From f50b64cab58025e080f994147b75a8ffc55d2b35 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 30 Mar 2018 12:37:04 +1100 Subject: [PATCH] py/runtime: Be sure that non-intercepted thrown object is an exception. The VM expects that, if mp_resume() returns MP_VM_RETURN_EXCEPTION, then the returned value is an exception instance (eg to add a traceback to it). It's possible that a value passed to a generator's throw() is not an exception so must be explicitly checked for if the thrown value is not intercepted by the generator. Thanks to @jepler for finding the bug. --- py/runtime.c | 2 +- tests/basics/gen_yield_from_throw3.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/py/runtime.c b/py/runtime.c index ca68fe982d..219ec22dee 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1282,7 +1282,7 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th // will be propagated up. This behavior is approved by test_pep380.py // test_delegation_of_close_to_non_generator(), // test_delegating_throw_to_non_generator() - *ret_val = throw_value; + *ret_val = mp_make_raise_obj(throw_value); return MP_VM_RETURN_EXCEPTION; } } diff --git a/tests/basics/gen_yield_from_throw3.py b/tests/basics/gen_yield_from_throw3.py index 0f6c7c8429..85b6f71f99 100644 --- a/tests/basics/gen_yield_from_throw3.py +++ b/tests/basics/gen_yield_from_throw3.py @@ -28,3 +28,30 @@ print(g.throw(123)) g = gen() print(next(g)) print(g.throw(ZeroDivisionError)) + +# this user-defined generator doesn't have a throw() method +class Iter2: + def __iter__(self): + return self + + def __next__(self): + return 1 + +def gen2(): + yield from Iter2() + +# the thrown ValueError is not intercepted by the user class +g = gen2() +print(next(g)) +try: + g.throw(ValueError) +except: + print('ValueError') + +# the thrown 123 is not an exception so raises a TypeError +g = gen2() +print(next(g)) +try: + g.throw(123) +except TypeError: + print('TypeError')