bpo-35943: Prevent PyImport_GetModule() from returning a partially-initialized module (GH-15057)
This commit is contained in:
parent
60bba83b5d
commit
37c2220698
|
@ -0,0 +1,2 @@
|
|||
The function :c:func:`PyImport_GetModule` now ensures any module it returns is fully initialized.
|
||||
Patch by Joannah Nanjekye.
|
|
@ -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);
|
||||
if (import_ensure_initialized(tstate, mod, name) < 0) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(value);
|
||||
}
|
||||
Py_XDECREF(spec);
|
||||
}
|
||||
else {
|
||||
Py_XDECREF(mod);
|
||||
|
|
Loading…
Reference in New Issue