diff --git a/Lib/test/test_interpreters/test_api.py b/Lib/test/test_interpreters/test_api.py index aac3cdd717668c..65cb5e17234dea 100644 --- a/Lib/test/test_interpreters/test_api.py +++ b/Lib/test/test_interpreters/test_api.py @@ -1683,6 +1683,25 @@ def get_count(): self.assertEqual(after, 0) self.assertEqual(counts, [0, 1, 4]) + def test_surrogate_filename_in___main__(self): + interp = interpreters.create() + import __main__ + orig_file = getattr(__main__, '__file__', None) + try: + for surrogate in ('\ud800', '\udcff'): + with self.subTest(surrogate=ascii(surrogate)): + __main__.__file__ = f'my_script_{surrogate}.py' + res = interp.call(lambda x: x, [1]) + self.assertEqual(res, [1]) + finally: + if orig_file is None: + try: + del __main__.__file__ + except AttributeError: + pass + else: + __main__.__file__ = orig_file + def test_raises(self): interp = interpreters.create() with self.assertRaises(ExecutionFailed): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-22-03-54-22.gh-issue-156122.lYvmDy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-22-03-54-22.gh-issue-156122.lYvmDy.rst new file mode 100644 index 00000000000000..b5a5c4fdc3250f --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-22-03-54-22.gh-issue-156122.lYvmDy.rst @@ -0,0 +1,2 @@ +Fix crash when module filenames containing lone surrogates are used during +cross-interpreter unpickling. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index b8cd6025c20ba5..3a8ab138c5cac4 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -991,14 +991,17 @@ _PyModule_GetFilenameUTF8(PyObject *mod, char *buffer, Py_ssize_t maxlen) size = 0; } else { - const char *filename = PyUnicode_AsUTF8AndSize(filenameobj, &size); - assert(size >= 0); - if (size > maxlen) { - size = -1; - PyErr_SetString(PyExc_ValueError, "__file__ too long"); - } - else { - (void)strcpy(buffer, filename); + PyObject *bytes = PyUnicode_EncodeFSDefault(filenameobj); + if (bytes != NULL) { + size = PyBytes_GET_SIZE(bytes); + if (size > maxlen) { + size = -1; + PyErr_SetString(PyExc_ValueError, "__file__ too long"); + } + else { + memcpy(buffer, PyBytes_AS_STRING(bytes), size + 1); + } + Py_DECREF(bytes); } } Py_DECREF(filenameobj);