Skip to content

Commit 8047340

Browse files
committed
py: Handle case of return within the finally block of try-finally.
Addresses issue adafruit#1636.
1 parent 117158f commit 8047340

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

py/vm.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,14 @@ unwind_jump:;
10321032

10331033
ENTRY(MP_BC_RETURN_VALUE):
10341034
MARK_EXC_IP_SELECTIVE();
1035+
// These next 3 lines pop a try-finally exception handler, if one
1036+
// is there on the exception stack. Without this the finally block
1037+
// is executed a second time when the return is executed, because
1038+
// the try-finally exception handler is still on the stack.
1039+
// TODO Possibly find a better way to handle this case.
1040+
if (currently_in_except_block) {
1041+
POP_EXC_BLOCK();
1042+
}
10351043
unwind_return:
10361044
while (exc_sp >= exc_stack) {
10371045
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# test 'return' within the finally block
2+
# it should swallow the exception
3+
4+
# simple case
5+
def f():
6+
try:
7+
raise ValueError()
8+
finally:
9+
print('finally')
10+
return 0
11+
print('got here')
12+
print(f())
13+
14+
# nested, return in outer
15+
def f():
16+
try:
17+
try:
18+
raise ValueError
19+
finally:
20+
print('finally 1')
21+
print('got here')
22+
finally:
23+
print('finally 2')
24+
return 2
25+
print('got here')
26+
print(f())
27+
28+
# nested, return in inner
29+
def f():
30+
try:
31+
try:
32+
raise ValueError
33+
finally:
34+
print('finally 1')
35+
return 1
36+
print('got here')
37+
finally:
38+
print('finally 2')
39+
print('got here')
40+
print(f())
41+
42+
# nested, return in inner and outer
43+
def f():
44+
try:
45+
try:
46+
raise ValueError
47+
finally:
48+
print('finally 1')
49+
return 1
50+
print('got here')
51+
finally:
52+
print('finally 2')
53+
return 2
54+
print('got here')
55+
print(f())
56+
57+
# nested with reraise
58+
def f():
59+
try:
60+
try:
61+
raise ValueError
62+
except:
63+
raise
64+
print('got here')
65+
finally:
66+
print('finally')
67+
return 0
68+
print('got here')
69+
print(f())
70+
71+
# triple nesting with reraise
72+
def f():
73+
try:
74+
try:
75+
try:
76+
raise ValueError
77+
except:
78+
raise
79+
except:
80+
raise
81+
finally:
82+
print('finally')
83+
return 0
84+
print(f())
85+
86+
# exception when matching exception
87+
def f():
88+
try:
89+
raise ValueError
90+
except NonExistingError:
91+
pass
92+
finally:
93+
print('finally')
94+
return 0
95+
print(f())
96+
97+
# raising exception class, not instance
98+
def f():
99+
try:
100+
raise ValueError
101+
finally:
102+
print('finally')
103+
return 0
104+
print(f())

0 commit comments

Comments
 (0)