From 37c22206981f52ae35c28b39f7530f8438afbfdb Mon Sep 17 00:00:00 2001 From: Joannah Nanjekye <33177550+nanjekyejoannah@users.noreply.github.com> Date: Wed, 11 Sep 2019 13:47:39 +0100 Subject: [PATCH] bpo-35943: Prevent PyImport_GetModule() from returning a partially-initialized module (GH-15057) --- .../2019-07-31-15-52-51.bpo-35943.-KswoB.rst | 2 + Python/import.c | 69 ++++++++++++------- 2 files changed, 48 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-07-31-15-52-51.bpo-35943.-KswoB.rst 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 @@ -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, @@ -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); -- 2.40.0