Skip to content

Commit 905d419

Browse files
[3.12] GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104760)
GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104674) (cherry picked from commit 357bed0) Co-authored-by: Brandt Bucher <[email protected]>
1 parent 25b5ce7 commit 905d419

File tree

4 files changed

+47
-7
lines changed

4 files changed

+47
-7
lines changed

Doc/c-api/veryhigh.rst

+8
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ the same library that the Python runtime is using.
167167
event loops, as done in the :file:`Modules/_tkinter.c` in the
168168
Python source code.
169169
170+
.. versionchanged:: 3.12
171+
This function is only called from the
172+
:ref:`main interpreter <sub-interpreter-support>`.
173+
170174
171175
.. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *)
172176
@@ -187,6 +191,10 @@ the same library that the Python runtime is using.
187191
:c:func:`PyMem_RawRealloc`, instead of being allocated by
188192
:c:func:`PyMem_Malloc` or :c:func:`PyMem_Realloc`.
189193
194+
.. versionchanged:: 3.12
195+
This function is only called from the
196+
:ref:`main interpreter <sub-interpreter-support>`.
197+
190198
.. c:function:: PyObject* PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
191199
192200
This is a simplified interface to :c:func:`PyRun_StringFlags` below, leaving

Doc/whatsnew/3.12.rst

+9
Original file line numberDiff line numberDiff line change
@@ -1476,6 +1476,15 @@ Porting to Python 3.12
14761476
Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12)
14771477
already disallows creating classes whose metaclass overrides ``tp_new``.
14781478

1479+
* :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no
1480+
longer called in :ref:`subinterpreters <sub-interpreter-support>`. This is
1481+
because clients generally rely on process-wide global state (since these
1482+
callbacks have no way of recovering extension module state).
1483+
1484+
This also avoids situations where extensions may find themselves running in a
1485+
subinterpreter that they don't support (or haven't yet been loaded in). See
1486+
:gh:`104668` for more info.
1487+
14791488
Deprecated
14801489
----------
14811490

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer`
2+
in subinterpreters, since it's generally difficult to avoid using global
3+
state in their registered callbacks. This also avoids situations where
4+
extensions may find themselves running in a subinterpreter they don't
5+
support (or haven't yet been loaded in).

Parser/myreadline.c

+25-7
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp)
4545
#endif
4646

4747
while (1) {
48-
if (PyOS_InputHook != NULL) {
48+
if (PyOS_InputHook != NULL &&
49+
// GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
50+
_Py_IsMainInterpreter(tstate->interp))
51+
{
4952
(void)(PyOS_InputHook)();
5053
}
5154

@@ -131,7 +134,10 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn)
131134
wbuf = wbuf_local;
132135
wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1;
133136
while (1) {
134-
if (PyOS_InputHook != NULL) {
137+
if (PyOS_InputHook != NULL &&
138+
// GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
139+
_Py_IsMainInterpreter(tstate->interp))
140+
{
135141
(void)(PyOS_InputHook)();
136142
}
137143
if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) {
@@ -389,11 +395,23 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
389395
* a tty. This can happen, for example if python is run like
390396
* this: python -i < test1.py
391397
*/
392-
if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout)))
393-
rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt);
394-
else
395-
rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout,
396-
prompt);
398+
if (!isatty(fileno(sys_stdin)) || !isatty(fileno(sys_stdout)) ||
399+
// GH-104668: Don't call global callbacks like PyOS_InputHook or
400+
// PyOS_ReadlineFunctionPointer from subinterpreters, since it seems
401+
// like there's no good way for users (like readline and tkinter) to
402+
// avoid using global state to manage them. Plus, we generally don't
403+
// want to cause trouble for libraries that don't know/care about
404+
// subinterpreter support. If libraries really need better APIs that
405+
// work per-interpreter and have ways to access module state, we can
406+
// certainly add them later (but for now we'll cross our fingers and
407+
// hope that nobody actually cares):
408+
!_Py_IsMainInterpreter(tstate->interp))
409+
{
410+
rv = PyOS_StdioReadline(sys_stdin, sys_stdout, prompt);
411+
}
412+
else {
413+
rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt);
414+
}
397415
Py_END_ALLOW_THREADS
398416

399417
PyThread_release_lock(_PyOS_ReadlineLock);

0 commit comments

Comments
 (0)