Skip to content

Commit

Permalink
bpo-35943: Prevent PyImport_GetModule() from returning a partially-in…
Browse files Browse the repository at this point in the history
…itialized module (GH-15057)
  • Loading branch information
nanjekyejoannah authored and brettcannon committed Sep 11, 2019
1 parent 60bba83 commit 37c2220
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The function :c:func:`PyImport_GetModule` now ensures any module it returns is fully initialized.
Patch by Joannah Nanjekye.
69 changes: 46 additions & 23 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,33 @@ import_get_module(PyThreadState *tstate, PyObject *name)
}


PyObject *
PyImport_GetModule(PyObject *name)
static int
import_ensure_initialized(PyThreadState *tstate, PyObject *mod, PyObject *name)
{
PyThreadState *tstate = _PyThreadState_GET();
return import_get_module(tstate, name);
PyInterpreterState *interp = tstate->interp;
PyObject *spec;

_Py_IDENTIFIER(__spec__);
_Py_IDENTIFIER(_lock_unlock_module);

/* Optimization: only call _bootstrap._lock_unlock_module() if
__spec__._initializing is true.
NOTE: because of this, initializing must be set *before*
stuffing the new module in sys.modules.
*/
spec = _PyObject_GetAttrId(mod, &PyId___spec__);
int busy = _PyModuleSpec_IsInitializing(spec);
Py_XDECREF(spec);
if (busy) {
/* Wait until module is done importing. */
PyObject *value = _PyObject_CallMethodIdOneArg(
interp->importlib, &PyId__lock_unlock_module, name);
if (value == NULL) {
return -1;
}
Py_DECREF(value);
}
return 0;
}


Expand Down Expand Up @@ -1461,6 +1483,7 @@ PyImport_ImportModule(const char *name)
return result;
}


/* Import a module without blocking
*
* At first it tries to fetch the module from sys.modules. If the module was
Expand Down Expand Up @@ -1762,6 +1785,23 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name)
return mod;
}

PyObject *
PyImport_GetModule(PyObject *name)
{
PyThreadState *tstate = _PyThreadState_GET();
PyObject *mod;

mod = import_get_module(tstate, name);
if (mod != NULL && mod != Py_None) {
if (import_ensure_initialized(tstate, mod, name) < 0) {
Py_DECREF(mod);
remove_importlib_frames(tstate);
return NULL;
}
}
return mod;
}

PyObject *
PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
PyObject *locals, PyObject *fromlist,
Expand Down Expand Up @@ -1817,26 +1857,9 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
}

if (mod != NULL && mod != Py_None) {
_Py_IDENTIFIER(__spec__);
_Py_IDENTIFIER(_lock_unlock_module);
PyObject *spec;

/* Optimization: only call _bootstrap._lock_unlock_module() if
__spec__._initializing is true.
NOTE: because of this, initializing must be set *before*
stuffing the new module in sys.modules.
*/
spec = _PyObject_GetAttrId(mod, &PyId___spec__);
if (_PyModuleSpec_IsInitializing(spec)) {
PyObject *value = _PyObject_CallMethodIdOneArg(
interp->importlib, &PyId__lock_unlock_module, abs_name);
if (value == NULL) {
Py_DECREF(spec);
goto error;
}
Py_DECREF(value);
if (import_ensure_initialized(tstate, mod, name) < 0) {
goto error;
}
Py_XDECREF(spec);
}
else {
Py_XDECREF(mod);
Expand Down

0 comments on commit 37c2220

Please sign in to comment.