Skip to content

Commit 69cb777

Browse files
Fix crash in Interpreter.call() with lone surrogate in __main__.__file__
1 parent b2c7b34 commit 69cb777

5 files changed

Lines changed: 23 additions & 5 deletions

File tree

Include/internal/pycore_moduleobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static inline PyObject* _PyModule_GetDict(PyObject *mod) {
7272
}
7373

7474
extern PyObject * _PyModule_GetFilenameObject(PyObject *);
75-
extern Py_ssize_t _PyModule_GetFilenameUTF8(
75+
extern Py_ssize_t _PyModule_GetFilename(
7676
PyObject *module,
7777
char *buffer,
7878
Py_ssize_t maxlen);

Lib/test/test_interpreters/test_api.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,6 +1873,13 @@ def test_call_in_thread(self):
18731873
t.join()
18741874
self.assertIsNotNone(ctx.caught)
18751875

1876+
def test_call_with_surrogate_in_main_filename(self):
1877+
# https://github.com/python/cpython/issues/156122
1878+
import __main__
1879+
__main__.__file__ = "bad\ud800.py"
1880+
1881+
interp = interpreters.create()
1882+
interp.call(lambda x: x, [1])
18761883

18771884
class TestIsShareable(TestBase):
18781885

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash in :method:`concurrent.interpreters.Interpreter.call` when
2+
``__main__.__file__`` contains lone surrogates.

Objects/moduleobject.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ PyModule_GetFilename(PyObject *m)
975975
}
976976

977977
Py_ssize_t
978-
_PyModule_GetFilenameUTF8(PyObject *mod, char *buffer, Py_ssize_t maxlen)
978+
_PyModule_GetFilename(PyObject *mod, char *buffer, Py_ssize_t maxlen)
979979
{
980980
// We "return" an empty string for an invalid module
981981
// and for a missing, empty, or invalid filename.
@@ -991,16 +991,25 @@ _PyModule_GetFilenameUTF8(PyObject *mod, char *buffer, Py_ssize_t maxlen)
991991
size = 0;
992992
}
993993
else {
994-
const char *filename = PyUnicode_AsUTF8AndSize(filenameobj, &size);
995-
assert(size >= 0);
994+
char *filename;
995+
PyObject *bytes = PyUnicode_EncodeFSDefault(filenameobj);
996+
if (bytes == NULL) {
997+
goto exit;
998+
}
999+
if (PyBytes_AsStringAndSize(bytes, &filename, &size) < 0) {
1000+
Py_DECREF(bytes);
1001+
goto exit;
1002+
}
9961003
if (size > maxlen) {
9971004
size = -1;
9981005
PyErr_SetString(PyExc_ValueError, "__file__ too long");
9991006
}
10001007
else {
10011008
(void)strcpy(buffer, filename);
10021009
}
1010+
Py_DECREF(bytes);
10031011
}
1012+
exit:
10041013
Py_DECREF(filenameobj);
10051014
return size;
10061015
}

Python/crossinterp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ _Py_GetMainfile(char *buffer, size_t maxlen)
2828
Py_XDECREF(module);
2929
return -1;
3030
}
31-
Py_ssize_t size = _PyModule_GetFilenameUTF8(module, buffer, maxlen);
31+
Py_ssize_t size = _PyModule_GetFilename(module, buffer, maxlen);
3232
Py_DECREF(module);
3333
return size;
3434
}

0 commit comments

Comments
 (0)