Skip to content

Commit f9e132f

Browse files
maybe_switch_to_main_interpreter() -> switch_to_main_interpreter()
1 parent 2d7ee11 commit f9e132f

File tree

1 file changed

+58
-51
lines changed

1 file changed

+58
-51
lines changed

Python/import.c

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,48 +1527,22 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name)
15271527
}
15281528

15291529
static PyThreadState *
1530-
maybe_switch_to_main_interpreter(PyThreadState *tstate)
1530+
switch_to_main_interpreter(PyThreadState *tstate)
15311531
{
1532-
PyThreadState *main_tstate = tstate;
15331532
if (_Py_IsMainInterpreter(tstate->interp)) {
1534-
/* There's no need to switch. */
1535-
}
1536-
else if (check_multi_interp_extensions(tstate->interp)) {
1537-
/*
1538-
If the module is single-phase init then the import will fail.
1539-
However, the module's init function will still get run.
1540-
That means it may still store state in the shared-object/DLL
1541-
address space (which never gets closed/cleared), including
1542-
objects (e.g. static types).
1543-
1544-
This is a problem for isolated subinterpreters since each
1545-
has its own object allocator. If the loaded shared-object
1546-
still holds a reference to an object after the corresponding
1547-
interpreter has finalized then either we must let it leak
1548-
or else any later use of that object by another interpreter
1549-
(or across multiple init-fini cycles) will crash the process.
1550-
1551-
We avoid the problem by first loading the module
1552-
in the main interpreter.
1553-
1554-
Here's another complication we avoid: the module's init
1555-
function might register callbacks, whether in Python
1556-
(e.g. sys.stdin, atexit) or in linked libraries.
1557-
Thus we cannot just dlclose() the module
1558-
in this error case.
1559-
*/
1560-
main_tstate = PyThreadState_New(_PyInterpreterState_Main());
1561-
if (main_tstate == NULL) {
1562-
return NULL;
1563-
}
1564-
main_tstate->_whence = _PyThreadState_WHENCE_EXEC;
1533+
return tstate;
1534+
}
1535+
PyThreadState *main_tstate = PyThreadState_New(_PyInterpreterState_Main());
1536+
if (main_tstate == NULL) {
1537+
return NULL;
1538+
}
1539+
main_tstate->_whence = _PyThreadState_WHENCE_EXEC;
15651540
#ifndef NDEBUG
1566-
PyThreadState *old_tstate = PyThreadState_Swap(main_tstate);
1567-
assert(old_tstate == tstate);
1541+
PyThreadState *old_tstate = PyThreadState_Swap(main_tstate);
1542+
assert(old_tstate == tstate);
15681543
#else
1569-
(void)PyThreadState_Swap(main_tstate);
1544+
(void)PyThreadState_Swap(main_tstate);
15701545
#endif
1571-
}
15721546
return main_tstate;
15731547
}
15741548

@@ -1924,27 +1898,58 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
19241898
* multi-phase init until after we call its init function. Even
19251899
* in isolated interpreters (that do not support single-phase init),
19261900
* the init function will run without restriction. For multi-phase
1927-
* init modules that isn't a problem because the init function runs
1928-
* PyModuleDef_Init() on the module's def and then returns it.
1901+
* init modules that isn't a problem because the init function only
1902+
* runs PyModuleDef_Init() on the module's def and then returns it.
19291903
*
19301904
* However, for single-phase init the module's init function will
19311905
* create the module, create other objects (and allocate other
19321906
* memory), populate it and its module state, and initialze static
19331907
* types. Some modules store other objects and data in global C
19341908
* variables and register callbacks with the runtime/stdlib or
1935-
* event external libraries. That's a problem for isolated
1936-
* interpreters since all of that happens and only then will
1937-
* the import fail. Memory will leak, callbacks will still
1938-
* get used, and sometimes there will be memory access
1939-
* violations and use-after-free crashes.
1909+
* even external libraries (which is part of why we can't just
1910+
* dlclose() the module in the error case). That's a problem
1911+
* for isolated interpreters since all of the above happens
1912+
* and only then * will the import fail. Memory will leak,
1913+
* callbacks will still get used, and sometimes there
1914+
* will be crashes (memory access violations
1915+
* and use-after-free).
1916+
*
1917+
* To put it another way, if the module is single-phase init
1918+
* then the import will probably break interpreter isolation
1919+
* and should fail ASAP. However, the module's init function
1920+
* will still get run. That means it may still store state
1921+
* in the shared-object/DLL address space (which never gets
1922+
* closed/cleared), including objects (e.g. static types).
1923+
* This is a problem for isolated subinterpreters since each
1924+
* has its own object allocator. If the loaded shared-object
1925+
* still holds a reference to an object after the corresponding
1926+
* interpreter has finalized then either we must let it leak
1927+
* or else any later use of that object by another interpreter
1928+
* (or across multiple init-fini cycles) will crash the process.
19401929
*
1941-
* To avoid that, we make sure the module's init function is always
1942-
* run first with the main interpreter active. If it was already
1943-
* the main interpreter then we can continue loading the module
1944-
* like normal. Otherwise, right after the init function, we switch
1945-
* back to the subinterpreter, check for single-phase init, and
1946-
* then continue loading like normal. */
1947-
PyThreadState *main_tstate = maybe_switch_to_main_interpreter(tstate);
1930+
* To avoid all of that, we make sure the module's init function
1931+
* is always run first with the main interpreter active. If it was
1932+
* already the main interpreter then we can continue loading the
1933+
* module like normal. Otherwise, right after the init function,
1934+
* we take care of some import state bookkeeping, switch back
1935+
* to the subinterpreter, check for single-phase init,
1936+
* and then continue loading like normal. */
1937+
1938+
PyThreadState *main_tstate = NULL;
1939+
if (!_Py_IsMainInterpreter(tstate->interp)) {
1940+
/* We *could* leave in place a legacy interpreter here
1941+
* (one that shares obmalloc/GIL with main interp),
1942+
* but there isn't a big advantage, we anticipate
1943+
* such interpreters will be increasingly uncommon,
1944+
* and the code is a bit simpler if we always switch
1945+
* to the main interpreter. */
1946+
main_tstate = switch_to_main_interpreter(tstate);
1947+
if (main_tstate == NULL) {
1948+
return NULL;
1949+
}
1950+
assert(main_tstate != tstate);
1951+
// XXX Get import lock.
1952+
}
19481953

19491954
struct _Py_ext_module_loader_result res;
19501955
int rc = _PyImport_RunModInitFunc(p0, info, &res);
@@ -1984,6 +1989,8 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
19841989
if (res.kind == _Py_ext_module_kind_MULTIPHASE) {
19851990
assert_multiphase_def(def);
19861991
assert(mod == NULL);
1992+
/* Note that we cheat a little by not repeating the calls
1993+
* to _PyImport_GetModInitFunc() and _PyImport_RunModInitFunc(). */
19871994
mod = PyModule_FromDefAndSpec(def, spec);
19881995
if (mod == NULL) {
19891996
goto error;

0 commit comments

Comments
 (0)