https://github.com/python/cpython/commit/b9cbdde80d0d468dd40bbcef51a36db96ee15b9c commit: b9cbdde80d0d468dd40bbcef51a36db96ee15b9c branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: ZeroIntensity <[email protected]> date: 2025-12-15T23:30:00Z summary:
[3.14] gh-142737: Handle lost `io.open` in `_Py_FindSourceFile` (GH-142747) (GH-142773) gh-142737: Handle lost `io.open` in `_Py_FindSourceFile` (GH-142747) (cherry picked from commit f277781bba684322dffffe45cd878f4652ccf7e4) Co-authored-by: Bartosz Sławecki <[email protected]> files: A Misc/NEWS.d/next/Core_and_Builtins/2025-12-15-15-01-21.gh-issue-142737.xYXzeB.rst M Lib/test/test_traceback.py M Objects/call.c M Python/traceback.c diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index b21daeb1b67556..c87ad67ed05a3a 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -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 @@ -504,6 +504,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( diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-15-15-01-21.gh-issue-142737.xYXzeB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-15-15-01-21.gh-issue-142737.xYXzeB.rst new file mode 100644 index 00000000000000..8b743d1e49de21 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-15-15-01-21.gh-issue-142737.xYXzeB.rst @@ -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. diff --git a/Objects/call.c b/Objects/call.c index b1610dababd466..6e331a43899a06 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -726,6 +726,7 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, 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); diff --git a/Python/traceback.c b/Python/traceback.c index 86273da3c8ae3c..b9c9132c0c50c1 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -416,6 +416,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) { _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
