gh-142737: Handle lost io.open in _Py_FindSourceFile (GH-142747)

This commit is contained in:
Bartosz Sławecki 2025-12-15 23:58:50 +01:00 committed by GitHub
parent 790a46a449
commit f277781bba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 35 additions and 1 deletions

View file

@ -18,7 +18,7 @@
from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ,
requires_debug_ranges, has_no_debug_ranges,
requires_subprocess)
from test.support.os_helper import TESTFN, unlink
from test.support.os_helper import TESTFN, temp_dir, unlink
from test.support.script_helper import assert_python_ok, assert_python_failure, make_script
from test.support.import_helper import forget
from test.support import force_not_colorized, force_not_colorized_test_class
@ -524,6 +524,33 @@ def __del__(self):
b'ZeroDivisionError: division by zero']
self.assertEqual(stderr.splitlines(), expected)
@cpython_only
def test_lost_io_open(self):
# GH-142737: Display the traceback even if io.open is lost
crasher = textwrap.dedent("""\
import io
import traceback
# Trigger fallback mode
traceback._print_exception_bltin = None
del io.open
raise RuntimeError("should not crash")
""")
# Create a temporary script to exercise _Py_FindSourceFile
with temp_dir() as script_dir:
script = make_script(
script_dir=script_dir,
script_basename='tb_test_no_io_open',
source=crasher)
rc, stdout, stderr = assert_python_failure(script)
self.assertEqual(rc, 1) # Make sure it's not a crash
expected = [b'Traceback (most recent call last):',
f' File "{script}", line 6, in <module>'.encode(),
b'RuntimeError: should not crash']
self.assertEqual(stderr.splitlines(), expected)
def test_print_exception(self):
output = StringIO()
traceback.print_exception(

View file

@ -0,0 +1,3 @@
Tracebacks will be displayed in fallback mode even if :func:`io.open` is lost.
Previously, this would crash the interpreter.
Patch by Bartosz Sławecki.

View file

@ -729,6 +729,7 @@ _Py_COMP_DIAG_POP
PyObject * _PyObject_CallMethodFormat(PyThreadState *tstate, PyObject *callable,
const char *format, ...)
{
assert(callable != NULL);
va_list va;
va_start(va, format);
PyObject *retval = callmethod(tstate, callable, format, va);

View file

@ -415,6 +415,9 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *
npath = PyList_Size(syspath);
open = PyObject_GetAttr(io, &_Py_ID(open));
if (open == NULL) {
goto error;
}
for (i = 0; i < npath; i++) {
v = PyList_GetItem(syspath, i);
if (v == NULL) {