summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2019-08-21 16:07:12 +1000
committerDamien George <damien.p.george@gmail.com>2019-08-28 12:31:49 +1000
commit16f6169c88a5fd93b151149e561d177557fcc760 (patch)
tree9889ea0a1e34b56811b6d9931fa98aa270845cae
parent3d7455a0bb4caa3e80e7594eaedd6e72c056ebe9 (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.c9
-rw-r--r--tests/misc/print_exception.py10
2 files changed, 15 insertions, 4 deletions
diff --git a/py/vm.c b/py/vm.c
index 6a4634d00..64bddd6b5 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -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():