Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.12] GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104674) #104760

Merged
merged 3 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Doc/c-api/veryhigh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ the same library that the Python runtime is using.
event loops, as done in the :file:`Modules/_tkinter.c` in the
Python source code.

.. versionchanged:: 3.12
This function is only called from the
:ref:`main interpreter <sub-interpreter-support>`.


.. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *)

Expand All @@ -187,6 +191,10 @@ the same library that the Python runtime is using.
:c:func:`PyMem_RawRealloc`, instead of being allocated by
:c:func:`PyMem_Malloc` or :c:func:`PyMem_Realloc`.

.. versionchanged:: 3.12
This function is only called from the
:ref:`main interpreter <sub-interpreter-support>`.

.. c:function:: PyObject* PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)

This is a simplified interface to :c:func:`PyRun_StringFlags` below, leaving
Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,15 @@ Porting to Python 3.12
Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12)
already disallows creating classes whose metaclass overrides ``tp_new``.

* :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no
longer called in :ref:`subinterpreters <sub-interpreter-support>`. This is
because clients generally rely on process-wide global state (since these
callbacks have no way of recovering extension module state).

This also avoids situations where extensions may find themselves running in a
subinterpreter that they don't support (or haven't yet been loaded in). See
:gh:`104668` for more info.

Deprecated
----------

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer`
in subinterpreters, since it's generally difficult to avoid using global
state in their registered callbacks. This also avoids situations where
extensions may find themselves running in a subinterpreter they don't
support (or haven't yet been loaded in).
32 changes: 25 additions & 7 deletions Parser/myreadline.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp)
#endif

while (1) {
if (PyOS_InputHook != NULL) {
if (PyOS_InputHook != NULL &&
// GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
_Py_IsMainInterpreter(tstate->interp))
{
(void)(PyOS_InputHook)();
}

Expand Down Expand Up @@ -131,7 +134,10 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn)
wbuf = wbuf_local;
wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1;
while (1) {
if (PyOS_InputHook != NULL) {
if (PyOS_InputHook != NULL &&
// GH-104668: See PyOS_ReadlineFunctionPointer's comment below...
_Py_IsMainInterpreter(tstate->interp))
{
(void)(PyOS_InputHook)();
}
if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) {
Expand Down Expand Up @@ -389,11 +395,23 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
* a tty. This can happen, for example if python is run like
* this: python -i < test1.py
*/
if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout)))
rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt);
else
rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout,
prompt);
if (!isatty(fileno(sys_stdin)) || !isatty(fileno(sys_stdout)) ||
// GH-104668: Don't call global callbacks like PyOS_InputHook or
// PyOS_ReadlineFunctionPointer from subinterpreters, since it seems
// like there's no good way for users (like readline and tkinter) to
// avoid using global state to manage them. Plus, we generally don't
// want to cause trouble for libraries that don't know/care about
// subinterpreter support. If libraries really need better APIs that
// work per-interpreter and have ways to access module state, we can
// certainly add them later (but for now we'll cross our fingers and
// hope that nobody actually cares):
!_Py_IsMainInterpreter(tstate->interp))
{
rv = PyOS_StdioReadline(sys_stdin, sys_stdout, prompt);
}
else {
rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt);
}
Py_END_ALLOW_THREADS

PyThread_release_lock(_PyOS_ReadlineLock);
Expand Down