Commit 6cc0a3a7 authored by Stefan Behnel's avatar Stefan Behnel

Prevent calling into CPython with a live exception set while trying to match...

Prevent calling into CPython with a live exception set while trying to match non-trivial exception patterns in an "except" clause.
parent 63de2433
...@@ -51,6 +51,9 @@ Features added ...@@ -51,6 +51,9 @@ Features added
Bugs fixed Bugs fixed
---------- ----------
* Catching exceptions with a non-trivial exception pattern could call into
CPython with a live exception set.
* Line tracing did not include generators and coroutines. * Line tracing did not include generators and coroutines.
(Github issue #1949) (Github issue #1949)
......
...@@ -7165,19 +7165,42 @@ class ExceptClauseNode(Node): ...@@ -7165,19 +7165,42 @@ class ExceptClauseNode(Node):
def generate_handling_code(self, code, end_label): def generate_handling_code(self, code, end_label):
code.mark_pos(self.pos) code.mark_pos(self.pos)
if self.pattern: if self.pattern:
has_non_literals = not all(
pattern.is_literal or (pattern.entry and pattern.entry.is_const)
for pattern in self.pattern)
if has_non_literals:
# For non-trivial exception check expressions, hide the live exception from C-API calls.
exc_vars = [code.funcstate.allocate_temp(py_object_type, manage_ref=True)
for _ in range(3)]
code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrFetchRestore", "Exceptions.c"))
code.putln("__Pyx_ErrFetch(&%s, &%s, &%s);" % tuple(exc_vars))
code.globalstate.use_utility_code(UtilityCode.load_cached("FastTypeChecks", "ModuleSetupCode.c"))
exc_test_func = "__Pyx_PyErr_GivenExceptionMatches(%s, %%s)" % exc_vars[0]
else:
exc_vars = ()
code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrExceptionMatches", "Exceptions.c")) code.globalstate.use_utility_code(UtilityCode.load_cached("PyErrExceptionMatches", "Exceptions.c"))
exc_test_func = "__Pyx_PyErr_ExceptionMatches(%s)"
exc_tests = [] exc_tests = []
for pattern in self.pattern: for pattern in self.pattern:
pattern.generate_evaluation_code(code) pattern.generate_evaluation_code(code)
exc_tests.append("__Pyx_PyErr_ExceptionMatches(%s)" % pattern.py_result()) exc_tests.append(exc_test_func % pattern.py_result())
match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False) match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln( code.putln("%s = %s;" % (match_flag, ' || '.join(exc_tests)))
"%s = %s;" % (match_flag, ' || '.join(exc_tests)))
for pattern in self.pattern: for pattern in self.pattern:
pattern.generate_disposal_code(code) pattern.generate_disposal_code(code)
pattern.free_temps(code) pattern.free_temps(code)
if has_non_literals:
code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(exc_vars))
code.putln(' '.join(["%s = 0;" % var for var in exc_vars]))
for temp in exc_vars:
code.funcstate.release_temp(temp)
code.putln( code.putln(
"if (%s) {" % "if (%s) {" %
match_flag) match_flag)
...@@ -7196,8 +7219,7 @@ class ExceptClauseNode(Node): ...@@ -7196,8 +7219,7 @@ class ExceptClauseNode(Node):
code.putln("}") code.putln("}")
return return
exc_vars = [code.funcstate.allocate_temp(py_object_type, exc_vars = [code.funcstate.allocate_temp(py_object_type, manage_ref=True)
manage_ref=True)
for _ in range(3)] for _ in range(3)]
code.put_add_traceback(self.function_name) code.put_add_traceback(self.function_name)
# We always have to fetch the exception value even if # We always have to fetch the exception value even if
......
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