Commit bbef4d74 authored by Stefan Behnel's avatar Stefan Behnel

Return statements inside of nested try-except statements lead to an incorrect...

Return statements inside of nested try-except statements lead to an incorrect control flow graph that did not take the outer 'finally' clauses into account.
Closes https://github.com/cython/cython/issues/3666
parent 09979e15
......@@ -8,6 +8,10 @@ Cython Changelog
Bugs fixed
----------
* Nested try-except statements with multiple ``return`` statements could crash
due to incorrect deletion of the ``except as`` target variable.
(Github issue #3666)
* The ``@classmethod`` decorator no longer rejects unknown input from other decorators.
Patch by David Woods. (Github issue #3660)
......
......@@ -1198,8 +1198,6 @@ class ControlFlowAnalysis(CythonTransform):
if self.flow.loops:
self.flow.loops[-1].exceptions.append(descr)
self.flow.block = body_block
## XXX: Is it still required
body_block.add_child(entry_point)
self.flow.nextblock()
self._visit(node.body)
self.flow.exceptions.pop()
......@@ -1233,11 +1231,18 @@ class ControlFlowAnalysis(CythonTransform):
self.mark_position(node)
self.visitchildren(node)
for exception in self.flow.exceptions[::-1]:
if exception.finally_enter:
self.flow.block.add_child(exception.finally_enter)
if exception.finally_exit:
exception.finally_exit.add_child(self.flow.exit_point)
outer_exception_handlers = iter(self.flow.exceptions[::-1])
for handler in outer_exception_handlers:
if handler.finally_enter:
self.flow.block.add_child(handler.finally_enter)
if handler.finally_exit:
# 'return' goes to function exit, or to the next outer 'finally' clause
exit_point = self.flow.exit_point
for next_handler in outer_exception_handlers:
if next_handler.finally_enter:
exit_point = next_handler.finally_enter
break
handler.finally_exit.add_child(exit_point)
break
else:
if self.flow.block:
......
......@@ -258,6 +258,32 @@ def except_as_deletes_target_in_gen(x, a):
yield 6
def nested_except_gh3666(a=False, b=False):
"""
>>> nested_except_gh3666()
'A'
>>> nested_except_gh3666(a=True)
'B-V'
>>> nested_except_gh3666(a=True, b=True)
'B-V-T'
"""
try:
if a:
raise ValueError
return "A"
except TypeError as exc:
return "A-T"
except ValueError as exc:
try:
if b:
raise TypeError
return "B-V"
except ValueError as exc:
return "B-V-V"
except TypeError as exc:
return "B-V-T"
### Py3 feature tests
def print_function(*args):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment