aboutsummaryrefslogtreecommitdiff
path: root/py/vm.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-09-03 13:08:16 +1000
committerDamien George <damien.p.george@gmail.com>2018-09-03 13:08:16 +1000
commitb735208403a54774f9fd3d966f7c1a194c41870f (patch)
treebc91197e5af64043ad24e7d1de8373b304c0e637 /py/vm.c
parent828f771e327b932afc4865dbec53ce567dce45f5 (diff)
py/vm: Fix handling of finally-return with complex nested finallys.
Back in 8047340d7532ec32bc9f2d603bffc0bc9544297f basic support was added in the VM to handle return statements within a finally block. But it didn't cover all cases, in particular when some finally's were active and others inactive when the "return" was executed. This patch adds further support for return-within-finally by correctly managing the currently_in_except_block flag, and should fix all cases. The main point is that finally handlers remain on the exception stack even if they are active (currently being executed), and the unwind return code should only execute those finally's which are inactive. New tests are added for the cases which now pass.
Diffstat (limited to 'py/vm.c')
-rw-r--r--py/vm.c16
1 files changed, 5 insertions, 11 deletions
diff --git a/py/vm.c b/py/vm.c
index 498ecb491..bc596b0e8 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1063,17 +1063,11 @@ 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:
+ // Search for and execute finally handlers that aren't already active
while (exc_sp >= exc_stack) {
- if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
+ if (!currently_in_except_block && MP_TAGPTR_TAG1(exc_sp->val_sp)) {
+ // Found a finally handler that isn't active.
// Getting here the stack looks like:
// (..., X, [iter0, iter1, ...,] ret_val)
// where X is pointed to by exc_sp->val_sp and in the case
@@ -1092,10 +1086,10 @@ unwind_return:
// done (when WITH_CLEANUP or END_FINALLY reached).
PUSH(MP_OBJ_NEW_SMALL_INT(-1));
ip = exc_sp->handler;
- exc_sp--;
+ POP_EXC_BLOCK();
goto dispatch_loop;
}
- exc_sp--;
+ POP_EXC_BLOCK();
}
nlr_pop();
code_state->sp = sp;