diff options
author | Damien George <damien.p.george@gmail.com> | 2019-08-21 16:07:12 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2019-08-28 12:31:49 +1000 |
commit | 16f6169c88a5fd93b151149e561d177557fcc760 (patch) | |
tree | 9889ea0a1e34b56811b6d9931fa98aa270845cae | |
parent | 3d7455a0bb4caa3e80e7594eaedd6e72c056ebe9 (diff) |
py/vm: Don't add traceback info for exc's propagated through a finally.
With this patch exception tracebacks that go through a finally are improved
(less confusing, match CPython), and it makes finally's slightly more
efficient (in time and RAM) because they no longer need to add a traceback.
Partially fixes issue #2928.
-rw-r--r-- | py/vm.c | 9 | ||||
-rw-r--r-- | tests/misc/print_exception.py | 10 |
2 files changed, 15 insertions, 4 deletions
@@ -1359,10 +1359,11 @@ exception_handler: #if MICROPY_STACKLESS unwind_loop: #endif - // set file and line number that the exception occurred at - // TODO: don't set traceback for exceptions re-raised by END_FINALLY. - // But consider how to handle nested exceptions. - if (nlr.ret_val != &mp_const_GeneratorExit_obj) { + // Set traceback info (file and line number) where the exception occurred, but not for: + // - constant GeneratorExit object, because it's const + // - exceptions re-raised by END_FINALLY + if (nlr.ret_val != &mp_const_GeneratorExit_obj + && *code_state->ip != MP_BC_END_FINALLY) { const byte *ip = code_state->fun_bc->bytecode; ip = mp_decode_uint_skip(ip); // skip n_state ip = mp_decode_uint_skip(ip); // skip n_exc_stack diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py index 95431632f..08b2e4bc4 100644 --- a/tests/misc/print_exception.py +++ b/tests/misc/print_exception.py @@ -47,6 +47,16 @@ except Exception as e: print('caught') print_exc(e) +# Test that an exception propagated through a finally doesn't have a traceback added there +try: + try: + f() + finally: + print('finally') +except Exception as e: + print('caught') + print_exc(e) + # Here we have a function with lots of bytecode generated for a single source-line, and # there is an error right at the end of the bytecode. It should report the correct line. def f(): |