Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-102056: Fix a few bugs in error handling of exception printing code #102078

Merged
merged 4 commits into from
Feb 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Lib/test/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,37 @@ def run():
self.assertEqual(out, b'')
self.assertNotIn("Unhandled exception", err.decode())

def test_print_exception_gh_102056(self):
# This used to crash. See gh-102056.
script = r"""if True:
import time
import threading
import _thread

def f():
try:
f()
except RecursionError:
f()

def g():
try:
raise ValueError()
except* ValueError:
f()

def h():
time.sleep(1)
_thread.interrupt_main()

t = threading.Thread(target=h)
t.start()
g()
t.join()
"""

assert_python_failure("-c", script)

def test_bare_raise_in_brand_new_thread(self):
def bare_raise():
raise
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix error handling bugs in interpreter's exception printing code, which could cause a crash on infinite recursion.
23 changes: 16 additions & 7 deletions Python/pythonrun.c
Original file line number Diff line number Diff line change
Expand Up @@ -1246,8 +1246,7 @@ print_chained(struct exception_print_context* ctx, PyObject *value,
const char * message, const char *tag)
{
PyObject *f = ctx->file;

if (_Py_EnterRecursiveCall(" in print_chained") < 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#101966 also tries to fix this! Don't let that stop you from fixing it here though :)

if (_Py_EnterRecursiveCall(" in print_chained")) {
return -1;
}
bool need_close = ctx->need_close;
Expand Down Expand Up @@ -1374,7 +1373,9 @@ print_exception_group(struct exception_print_context *ctx, PyObject *value)
if (ctx->exception_group_depth == 0) {
ctx->exception_group_depth += 1;
}
print_exception(ctx, value);
if (print_exception(ctx, value) < 0) {
return -1;
}

PyObject *excs = ((PyBaseExceptionGroupObject *)value)->excs;
assert(excs && PyTuple_Check(excs));
Expand Down Expand Up @@ -1424,7 +1425,7 @@ print_exception_group(struct exception_print_context *ctx, PyObject *value)
PyObject *exc = PyTuple_GET_ITEM(excs, i);

if (!truncated) {
if (_Py_EnterRecursiveCall(" in print_exception_group") != 0) {
if (_Py_EnterRecursiveCall(" in print_exception_group")) {
return -1;
}
int res = print_exception_recursive(ctx, exc);
Expand Down Expand Up @@ -1477,22 +1478,30 @@ print_exception_group(struct exception_print_context *ctx, PyObject *value)
static int
print_exception_recursive(struct exception_print_context *ctx, PyObject *value)
{
if (_Py_EnterRecursiveCall(" in print_exception_recursive")) {
return -1;
}
if (ctx->seen != NULL) {
/* Exception chaining */
if (print_exception_cause_and_context(ctx, value) < 0) {
return -1;
goto error;
}
}
if (!_PyBaseExceptionGroup_Check(value)) {
if (print_exception(ctx, value) < 0) {
return -1;
goto error;
}
}
else if (print_exception_group(ctx, value) < 0) {
return -1;
goto error;
}
assert(!PyErr_Occurred());

_Py_LeaveRecursiveCall();
return 0;
error:
_Py_LeaveRecursiveCall();
return -1;
}

#define PyErr_MAX_GROUP_WIDTH 15
Expand Down