summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoannah Nanjekye <33177550+nanjekyejoannah@users.noreply.github.com>2019-09-11 13:47:39 +0100
committerBrett Cannon <54418+brettcannon@users.noreply.github.com>2019-09-11 13:47:39 +0100
commit37c22206981f52ae35c28b39f7530f8438afbfdb (patch)
treec22116bb330892a90d74b5211ec2b11d228dd42b
parent60bba83b5d9947fb3106325293e3a4e9c9cdea7e (diff)
downloadcpython-git-37c22206981f52ae35c28b39f7530f8438afbfdb.tar.gz
bpo-35943: Prevent PyImport_GetModule() from returning a partially-initialized module (GH-15057)
-rw-r--r--Misc/NEWS.d/next/Library/2019-07-31-15-52-51.bpo-35943.-KswoB.rst2
-rw-r--r--Python/import.c69
2 files changed, 48 insertions, 23 deletions
diff --git a/Misc/NEWS.d/next/Library/2019-07-31-15-52-51.bpo-35943.-KswoB.rst b/Misc/NEWS.d/next/Library/2019-07-31-15-52-51.bpo-35943.-KswoB.rst
new file mode 100644
index 0000000000..b1c55608f5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-07-31-15-52-51.bpo-35943.-KswoB.rst
@@ -0,0 +1,2 @@
+The function :c:func:`PyImport_GetModule` now ensures any module it returns is fully initialized.
+Patch by Joannah Nanjekye.
diff --git a/Python/import.c b/Python/import.c
index 5be4d196a3..6eb079d2a4 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -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;
}
@@ -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
@@ -1763,6 +1786,23 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name)
}
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,
int level)
@@ -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);