From 8047340d7532ec32bc9f2d603bffc0bc9544297f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 24 Dec 2015 12:47:39 +0000 Subject: [PATCH] py: Handle case of return within the finally block of try-finally. Addresses issue #1636. --- py/vm.c | 8 +++ tests/basics/try_finally_return2.py | 104 ++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 tests/basics/try_finally_return2.py diff --git a/py/vm.c b/py/vm.c index 8bf59f1e05..8c7c2265e4 100644 --- a/py/vm.c +++ b/py/vm.c @@ -1032,6 +1032,14 @@ unwind_jump:; ENTRY(MP_BC_RETURN_VALUE): MARK_EXC_IP_SELECTIVE(); + // These next 3 lines pop a try-finally exception handler, if one + // is there on the exception stack. Without this the finally block + // is executed a second time when the return is executed, because + // the try-finally exception handler is still on the stack. + // TODO Possibly find a better way to handle this case. + if (currently_in_except_block) { + POP_EXC_BLOCK(); + } unwind_return: while (exc_sp >= exc_stack) { if (MP_TAGPTR_TAG1(exc_sp->val_sp)) { diff --git a/tests/basics/try_finally_return2.py b/tests/basics/try_finally_return2.py new file mode 100644 index 0000000000..e3ea5f1eb8 --- /dev/null +++ b/tests/basics/try_finally_return2.py @@ -0,0 +1,104 @@ +# test 'return' within the finally block +# it should swallow the exception + +# simple case +def f(): + try: + raise ValueError() + finally: + print('finally') + return 0 + print('got here') +print(f()) + +# nested, return in outer +def f(): + try: + try: + raise ValueError + finally: + print('finally 1') + print('got here') + finally: + print('finally 2') + return 2 + print('got here') +print(f()) + +# nested, return in inner +def f(): + try: + try: + raise ValueError + finally: + print('finally 1') + return 1 + print('got here') + finally: + print('finally 2') + print('got here') +print(f()) + +# nested, return in inner and outer +def f(): + try: + try: + raise ValueError + finally: + print('finally 1') + return 1 + print('got here') + finally: + print('finally 2') + return 2 + print('got here') +print(f()) + +# nested with reraise +def f(): + try: + try: + raise ValueError + except: + raise + print('got here') + finally: + print('finally') + return 0 + print('got here') +print(f()) + +# triple nesting with reraise +def f(): + try: + try: + try: + raise ValueError + except: + raise + except: + raise + finally: + print('finally') + return 0 +print(f()) + +# exception when matching exception +def f(): + try: + raise ValueError + except NonExistingError: + pass + finally: + print('finally') + return 0 +print(f()) + +# raising exception class, not instance +def f(): + try: + raise ValueError + finally: + print('finally') + return 0 +print(f())