bpo-41994: Fix refcount issues in Python/import.c (GH-22632)

https://bugs.python.org/issue41994
This commit is contained in:
Serhiy Storchaka 2021-01-12 16:43:32 +02:00 committed by GitHub
parent 11d13e83ab
commit 4db8988420
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 63 deletions

View file

@ -13,8 +13,6 @@ PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module);
PyAPI_FUNC(void) _PyImport_AcquireLock(void); PyAPI_FUNC(void) _PyImport_AcquireLock(void);
PyAPI_FUNC(int) _PyImport_ReleaseLock(void); PyAPI_FUNC(int) _PyImport_ReleaseLock(void);
PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObject(PyObject *, PyObject *);
PyAPI_FUNC(int) _PyImport_FixupBuiltin( PyAPI_FUNC(int) _PyImport_FixupBuiltin(
PyObject *mod, PyObject *mod,
const char *name, /* UTF-8 encoded string */ const char *name, /* UTF-8 encoded string */

View file

@ -5,11 +5,6 @@
extern "C" { extern "C" {
#endif #endif
PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin(
PyThreadState *tstate,
const char *name /* UTF-8 encoded string */
);
#ifdef HAVE_FORK #ifdef HAVE_FORK
extern PyStatus _PyImport_ReInitLock(void); extern PyStatus _PyImport_ReInitLock(void);
#endif #endif

View file

@ -0,0 +1 @@
Fixed possible leak in ``import`` when ``sys.modules`` is not a ``dict``.

View file

@ -409,7 +409,7 @@ PyImport_GetMagicTag(void)
modules. A copy of the module's dictionary is stored by calling modules. A copy of the module's dictionary is stored by calling
_PyImport_FixupExtensionObject() immediately after the module initialization _PyImport_FixupExtensionObject() immediately after the module initialization
function succeeds. A copy can be retrieved from there by calling function succeeds. A copy can be retrieved from there by calling
_PyImport_FindExtensionObject(). import_find_extension().
Modules which do support multiple initialization set their m_size Modules which do support multiple initialization set their m_size
field to a non-negative number (indicating the size of the field to a non-negative number (indicating the size of the
@ -522,10 +522,14 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
if (mod == NULL) if (mod == NULL)
return NULL; return NULL;
mdict = PyModule_GetDict(mod); mdict = PyModule_GetDict(mod);
if (mdict == NULL) if (mdict == NULL) {
Py_DECREF(mod);
return NULL; return NULL;
if (PyDict_Update(mdict, def->m_base.m_copy)) }
if (PyDict_Update(mdict, def->m_base.m_copy)) {
Py_DECREF(mod);
return NULL; return NULL;
}
} }
else { else {
if (def->m_base.m_init == NULL) if (def->m_base.m_init == NULL)
@ -537,10 +541,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
Py_DECREF(mod); Py_DECREF(mod);
return NULL; return NULL;
} }
Py_DECREF(mod);
} }
if (_PyState_AddModule(tstate, mod, def) < 0) { if (_PyState_AddModule(tstate, mod, def) < 0) {
PyMapping_DelItem(modules, name); PyMapping_DelItem(modules, name);
Py_DECREF(mod);
return NULL; return NULL;
} }
@ -552,31 +556,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
return mod; return mod;
} }
PyObject *
_PyImport_FindExtensionObject(PyObject *name, PyObject *filename)
{
PyThreadState *tstate = _PyThreadState_GET();
return import_find_extension(tstate, name, filename);
}
PyObject *
_PyImport_FindBuiltin(PyThreadState *tstate, const char *name)
{
PyObject *res, *nameobj;
nameobj = PyUnicode_InternFromString(name);
if (nameobj == NULL)
return NULL;
res = import_find_extension(tstate, nameobj, nameobj);
Py_DECREF(nameobj);
return res;
}
/* Get the module object corresponding to a module name. /* Get the module object corresponding to a module name.
First check the modules dictionary if there's one there, First check the modules dictionary if there's one there,
if not, create a new one and insert it in the modules dictionary. if not, create a new one and insert it in the modules dictionary. */
Because the former action is most common, THIS DOES NOT RETURN A
'NEW' REFERENCE! */
static PyObject * static PyObject *
import_add_module(PyThreadState *tstate, PyObject *name) import_add_module(PyThreadState *tstate, PyObject *name)
@ -591,6 +574,7 @@ import_add_module(PyThreadState *tstate, PyObject *name)
PyObject *m; PyObject *m;
if (PyDict_CheckExact(modules)) { if (PyDict_CheckExact(modules)) {
m = PyDict_GetItemWithError(modules, name); m = PyDict_GetItemWithError(modules, name);
Py_XINCREF(m);
} }
else { else {
m = PyObject_GetItem(modules, name); m = PyObject_GetItem(modules, name);
@ -606,6 +590,7 @@ import_add_module(PyThreadState *tstate, PyObject *name)
if (m != NULL && PyModule_Check(m)) { if (m != NULL && PyModule_Check(m)) {
return m; return m;
} }
Py_XDECREF(m);
m = PyModule_NewObject(name); m = PyModule_NewObject(name);
if (m == NULL) if (m == NULL)
return NULL; return NULL;
@ -613,7 +598,6 @@ import_add_module(PyThreadState *tstate, PyObject *name)
Py_DECREF(m); Py_DECREF(m);
return NULL; return NULL;
} }
Py_DECREF(m); /* Yes, it still exists, in modules! */
return m; return m;
} }
@ -622,7 +606,17 @@ PyObject *
PyImport_AddModuleObject(PyObject *name) PyImport_AddModuleObject(PyObject *name)
{ {
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
return import_add_module(tstate, name); PyObject *mod = import_add_module(tstate, name);
if (mod) {
PyObject *ref = PyWeakref_NewRef(mod, NULL);
Py_DECREF(mod);
if (ref == NULL) {
return NULL;
}
mod = PyWeakref_GetObject(ref);
Py_DECREF(ref);
}
return mod; /* borrowed reference */
} }
@ -747,7 +741,7 @@ static PyObject *
module_dict_for_exec(PyThreadState *tstate, PyObject *name) module_dict_for_exec(PyThreadState *tstate, PyObject *name)
{ {
_Py_IDENTIFIER(__builtins__); _Py_IDENTIFIER(__builtins__);
PyObject *m, *d = NULL; PyObject *m, *d;
m = import_add_module(tstate, name); m = import_add_module(tstate, name);
if (m == NULL) if (m == NULL)
@ -762,10 +756,13 @@ module_dict_for_exec(PyThreadState *tstate, PyObject *name)
} }
if (r < 0) { if (r < 0) {
remove_module(tstate, name); remove_module(tstate, name);
Py_DECREF(m);
return NULL; return NULL;
} }
return d; /* Return a borrowed reference. */ Py_INCREF(d);
Py_DECREF(m);
return d;
} }
static PyObject * static PyObject *
@ -809,8 +806,10 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
} }
external = PyObject_GetAttrString(tstate->interp->importlib, external = PyObject_GetAttrString(tstate->interp->importlib,
"_bootstrap_external"); "_bootstrap_external");
if (external == NULL) if (external == NULL) {
Py_DECREF(d);
return NULL; return NULL;
}
res = _PyObject_CallMethodIdObjArgs(external, res = _PyObject_CallMethodIdObjArgs(external,
&PyId__fix_up_module, &PyId__fix_up_module,
d, name, pathname, cpathname, NULL); d, name, pathname, cpathname, NULL);
@ -819,6 +818,7 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
Py_DECREF(res); Py_DECREF(res);
res = exec_code_in_module(tstate, name, d, co); res = exec_code_in_module(tstate, name, d, co);
} }
Py_DECREF(d);
return res; return res;
} }
@ -912,8 +912,7 @@ is_builtin(PyObject *name)
that can handle the path item. Return None if no hook could; that can handle the path item. Return None if no hook could;
this tells our caller that the path based finder could not find this tells our caller that the path based finder could not find
a finder for this path item. Cache the result in a finder for this path item. Cache the result in
path_importer_cache. path_importer_cache. */
Returns a borrowed reference. */
static PyObject * static PyObject *
get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache, get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache,
@ -931,8 +930,10 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache,
return NULL; /* Shouldn't happen */ return NULL; /* Shouldn't happen */
importer = PyDict_GetItemWithError(path_importer_cache, p); importer = PyDict_GetItemWithError(path_importer_cache, p);
if (importer != NULL || _PyErr_Occurred(tstate)) if (importer != NULL || _PyErr_Occurred(tstate)) {
Py_XINCREF(importer);
return importer; return importer;
}
/* set path_importer_cache[p] to None to avoid recursion */ /* set path_importer_cache[p] to None to avoid recursion */
if (PyDict_SetItem(path_importer_cache, p, Py_None) != 0) if (PyDict_SetItem(path_importer_cache, p, Py_None) != 0)
@ -952,13 +953,11 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache,
_PyErr_Clear(tstate); _PyErr_Clear(tstate);
} }
if (importer == NULL) { if (importer == NULL) {
return Py_None; Py_RETURN_NONE;
} }
if (importer != NULL) { if (PyDict_SetItem(path_importer_cache, p, importer) < 0) {
int err = PyDict_SetItem(path_importer_cache, p, importer);
Py_DECREF(importer); Py_DECREF(importer);
if (err != 0) return NULL;
return NULL;
} }
return importer; return importer;
} }
@ -967,24 +966,19 @@ PyObject *
PyImport_GetImporter(PyObject *path) PyImport_GetImporter(PyObject *path)
{ {
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
PyObject *importer=NULL, *path_importer_cache=NULL, *path_hooks=NULL; PyObject *path_importer_cache = PySys_GetObject("path_importer_cache");
PyObject *path_hooks = PySys_GetObject("path_hooks");
path_importer_cache = PySys_GetObject("path_importer_cache"); if (path_importer_cache == NULL || path_hooks == NULL) {
path_hooks = PySys_GetObject("path_hooks"); return NULL;
if (path_importer_cache != NULL && path_hooks != NULL) {
importer = get_path_importer(tstate, path_importer_cache,
path_hooks, path);
} }
Py_XINCREF(importer); /* get_path_importer returns a borrowed reference */ return get_path_importer(tstate, path_importer_cache, path_hooks, path);
return importer;
} }
static PyObject* static PyObject*
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
{ {
PyObject *mod = _PyImport_FindExtensionObject(name, name); PyObject *mod = import_find_extension(tstate, name, name);
if (mod || _PyErr_Occurred(tstate)) { if (mod || _PyErr_Occurred(tstate)) {
Py_XINCREF(mod);
return mod; return mod;
} }
@ -1165,10 +1159,12 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
l = PyList_New(0); l = PyList_New(0);
if (l == NULL) { if (l == NULL) {
Py_DECREF(m);
goto err_return; goto err_return;
} }
err = PyDict_SetItemString(d, "__path__", l); err = PyDict_SetItemString(d, "__path__", l);
Py_DECREF(l); Py_DECREF(l);
Py_DECREF(m);
if (err != 0) if (err != 0)
goto err_return; goto err_return;
} }
@ -1177,6 +1173,7 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
goto err_return; goto err_return;
} }
m = exec_code_in_module(tstate, name, d, co); m = exec_code_in_module(tstate, name, d, co);
Py_DECREF(d);
if (m == NULL) { if (m == NULL) {
goto err_return; goto err_return;
} }
@ -1875,7 +1872,6 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
{ {
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
int ret; int ret;
PyObject *m;
ret = PyImport_ImportFrozenModuleObject(name); ret = PyImport_ImportFrozenModuleObject(name);
if (ret < 0) if (ret < 0)
@ -1883,9 +1879,7 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
if (ret == 0) { if (ret == 0) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
m = import_add_module(tstate, name); return import_add_module(tstate, name);
Py_XINCREF(m);
return m;
} }
/*[clinic input] /*[clinic input]
@ -2009,11 +2003,11 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
return NULL; return NULL;
} }
mod = _PyImport_FindExtensionObject(name, path); PyThreadState *tstate = _PyThreadState_GET();
mod = import_find_extension(tstate, name, path);
if (mod != NULL || PyErr_Occurred()) { if (mod != NULL || PyErr_Occurred()) {
Py_DECREF(name); Py_DECREF(name);
Py_DECREF(path); Py_DECREF(path);
Py_XINCREF(mod);
return mod; return mod;
} }