Skip to content

Commit 37c2220

Browse files
nanjekyejoannahbrettcannon
authored andcommitted
bpo-35943: Prevent PyImport_GetModule() from returning a partially-initialized module (GH-15057)
1 parent 60bba83 commit 37c2220

File tree

2 files changed

+48
-23
lines changed

2 files changed

+48
-23
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The function :c:func:`PyImport_GetModule` now ensures any module it returns is fully initialized.
2+
Patch by Joannah Nanjekye.

Python/import.c

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -387,11 +387,33 @@ import_get_module(PyThreadState *tstate, PyObject *name)
387387
}
388388

389389

390-
PyObject *
391-
PyImport_GetModule(PyObject *name)
390+
static int
391+
import_ensure_initialized(PyThreadState *tstate, PyObject *mod, PyObject *name)
392392
{
393-
PyThreadState *tstate = _PyThreadState_GET();
394-
return import_get_module(tstate, name);
393+
PyInterpreterState *interp = tstate->interp;
394+
PyObject *spec;
395+
396+
_Py_IDENTIFIER(__spec__);
397+
_Py_IDENTIFIER(_lock_unlock_module);
398+
399+
/* Optimization: only call _bootstrap._lock_unlock_module() if
400+
__spec__._initializing is true.
401+
NOTE: because of this, initializing must be set *before*
402+
stuffing the new module in sys.modules.
403+
*/
404+
spec = _PyObject_GetAttrId(mod, &PyId___spec__);
405+
int busy = _PyModuleSpec_IsInitializing(spec);
406+
Py_XDECREF(spec);
407+
if (busy) {
408+
/* Wait until module is done importing. */
409+
PyObject *value = _PyObject_CallMethodIdOneArg(
410+
interp->importlib, &PyId__lock_unlock_module, name);
411+
if (value == NULL) {
412+
return -1;
413+
}
414+
Py_DECREF(value);
415+
}
416+
return 0;
395417
}
396418

397419

@@ -1461,6 +1483,7 @@ PyImport_ImportModule(const char *name)
14611483
return result;
14621484
}
14631485

1486+
14641487
/* Import a module without blocking
14651488
*
14661489
* At first it tries to fetch the module from sys.modules. If the module was
@@ -1762,6 +1785,23 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name)
17621785
return mod;
17631786
}
17641787

1788+
PyObject *
1789+
PyImport_GetModule(PyObject *name)
1790+
{
1791+
PyThreadState *tstate = _PyThreadState_GET();
1792+
PyObject *mod;
1793+
1794+
mod = import_get_module(tstate, name);
1795+
if (mod != NULL && mod != Py_None) {
1796+
if (import_ensure_initialized(tstate, mod, name) < 0) {
1797+
Py_DECREF(mod);
1798+
remove_importlib_frames(tstate);
1799+
return NULL;
1800+
}
1801+
}
1802+
return mod;
1803+
}
1804+
17651805
PyObject *
17661806
PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
17671807
PyObject *locals, PyObject *fromlist,
@@ -1817,26 +1857,9 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
18171857
}
18181858

18191859
if (mod != NULL && mod != Py_None) {
1820-
_Py_IDENTIFIER(__spec__);
1821-
_Py_IDENTIFIER(_lock_unlock_module);
1822-
PyObject *spec;
1823-
1824-
/* Optimization: only call _bootstrap._lock_unlock_module() if
1825-
__spec__._initializing is true.
1826-
NOTE: because of this, initializing must be set *before*
1827-
stuffing the new module in sys.modules.
1828-
*/
1829-
spec = _PyObject_GetAttrId(mod, &PyId___spec__);
1830-
if (_PyModuleSpec_IsInitializing(spec)) {
1831-
PyObject *value = _PyObject_CallMethodIdOneArg(
1832-
interp->importlib, &PyId__lock_unlock_module, abs_name);
1833-
if (value == NULL) {
1834-
Py_DECREF(spec);
1835-
goto error;
1836-
}
1837-
Py_DECREF(value);
1860+
if (import_ensure_initialized(tstate, mod, name) < 0) {
1861+
goto error;
18381862
}
1839-
Py_XDECREF(spec);
18401863
}
18411864
else {
18421865
Py_XDECREF(mod);

0 commit comments

Comments
 (0)