diff options
author | Joannah Nanjekye <33177550+nanjekyejoannah@users.noreply.github.com> | 2019-09-11 12:47:39 (GMT) |
---|---|---|
committer | Brett Cannon <54418+brettcannon@users.noreply.github.com> | 2019-09-11 12:47:39 (GMT) |
commit | 37c22206981f52ae35c28b39f7530f8438afbfdb (patch) | |
tree | c22116bb330892a90d74b5211ec2b11d228dd42b | |
parent | 60bba83b5d9947fb3106325293e3a4e9c9cdea7e (diff) | |
download | cpython-37c22206981f52ae35c28b39f7530f8438afbfdb.zip cpython-37c22206981f52ae35c28b39f7530f8438afbfdb.tar.gz cpython-37c22206981f52ae35c28b39f7530f8438afbfdb.tar.bz2 |
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.rst | 2 | ||||
-rw-r--r-- | Python/import.c | 69 |
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 0000000..b1c5560 --- /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 5be4d19..6eb079d 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); |