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(int) _PyImport_ReleaseLock(void);
PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObject(PyObject *, PyObject *);
PyAPI_FUNC(int) _PyImport_FixupBuiltin(
PyObject *mod,
const char *name, /* UTF-8 encoded string */

View File

@ -5,11 +5,6 @@
extern "C" {
#endif
PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin(
PyThreadState *tstate,
const char *name /* UTF-8 encoded string */
);
#ifdef HAVE_FORK
extern PyStatus _PyImport_ReInitLock(void);
#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
_PyImport_FixupExtensionObject() immediately after the module initialization
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
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)
return NULL;
mdict = PyModule_GetDict(mod);
if (mdict == NULL)
if (mdict == NULL) {
Py_DECREF(mod);
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;
}
}
else {
if (def->m_base.m_init == NULL)
@ -537,10 +541,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
Py_DECREF(mod);
return NULL;
}
Py_DECREF(mod);
}
if (_PyState_AddModule(tstate, mod, def) < 0) {
PyMapping_DelItem(modules, name);
Py_DECREF(mod);
return NULL;
}
@ -552,31 +556,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
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.
First check the modules dictionary if there's one there,
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! */
if not, create a new one and insert it in the modules dictionary. */
static PyObject *
import_add_module(PyThreadState *tstate, PyObject *name)
@ -591,6 +574,7 @@ import_add_module(PyThreadState *tstate, PyObject *name)
PyObject *m;
if (PyDict_CheckExact(modules)) {
m = PyDict_GetItemWithError(modules, name);
Py_XINCREF(m);
}
else {
m = PyObject_GetItem(modules, name);
@ -606,6 +590,7 @@ import_add_module(PyThreadState *tstate, PyObject *name)
if (m != NULL && PyModule_Check(m)) {
return m;
}
Py_XDECREF(m);
m = PyModule_NewObject(name);
if (m == NULL)
return NULL;
@ -613,7 +598,6 @@ import_add_module(PyThreadState *tstate, PyObject *name)
Py_DECREF(m);
return NULL;
}
Py_DECREF(m); /* Yes, it still exists, in modules! */
return m;
}
@ -622,7 +606,17 @@ PyObject *
PyImport_AddModuleObject(PyObject *name)
{
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)
{
_Py_IDENTIFIER(__builtins__);
PyObject *m, *d = NULL;
PyObject *m, *d;
m = import_add_module(tstate, name);
if (m == NULL)
@ -762,10 +756,13 @@ module_dict_for_exec(PyThreadState *tstate, PyObject *name)
}
if (r < 0) {
remove_module(tstate, name);
Py_DECREF(m);
return NULL;
}
return d; /* Return a borrowed reference. */
Py_INCREF(d);
Py_DECREF(m);
return d;
}
static PyObject *
@ -809,8 +806,10 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
}
external = PyObject_GetAttrString(tstate->interp->importlib,
"_bootstrap_external");
if (external == NULL)
if (external == NULL) {
Py_DECREF(d);
return NULL;
}
res = _PyObject_CallMethodIdObjArgs(external,
&PyId__fix_up_module,
d, name, pathname, cpathname, NULL);
@ -819,6 +818,7 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
Py_DECREF(res);
res = exec_code_in_module(tstate, name, d, co);
}
Py_DECREF(d);
return res;
}
@ -912,8 +912,7 @@ is_builtin(PyObject *name)
that can handle the path item. Return None if no hook could;
this tells our caller that the path based finder could not find
a finder for this path item. Cache the result in
path_importer_cache.
Returns a borrowed reference. */
path_importer_cache. */
static PyObject *
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 */
importer = PyDict_GetItemWithError(path_importer_cache, p);
if (importer != NULL || _PyErr_Occurred(tstate))
if (importer != NULL || _PyErr_Occurred(tstate)) {
Py_XINCREF(importer);
return importer;
}
/* set path_importer_cache[p] to None to avoid recursion */
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);
}
if (importer == NULL) {
return Py_None;
Py_RETURN_NONE;
}
if (importer != NULL) {
int err = PyDict_SetItem(path_importer_cache, p, importer);
if (PyDict_SetItem(path_importer_cache, p, importer) < 0) {
Py_DECREF(importer);
if (err != 0)
return NULL;
return NULL;
}
return importer;
}
@ -967,24 +966,19 @@ PyObject *
PyImport_GetImporter(PyObject *path)
{
PyThreadState *tstate = _PyThreadState_GET();
PyObject *importer=NULL, *path_importer_cache=NULL, *path_hooks=NULL;
path_importer_cache = PySys_GetObject("path_importer_cache");
path_hooks = PySys_GetObject("path_hooks");
if (path_importer_cache != NULL && path_hooks != NULL) {
importer = get_path_importer(tstate, path_importer_cache,
path_hooks, path);
PyObject *path_importer_cache = PySys_GetObject("path_importer_cache");
PyObject *path_hooks = PySys_GetObject("path_hooks");
if (path_importer_cache == NULL || path_hooks == NULL) {
return NULL;
}
Py_XINCREF(importer); /* get_path_importer returns a borrowed reference */
return importer;
return get_path_importer(tstate, path_importer_cache, path_hooks, path);
}
static PyObject*
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)) {
Py_XINCREF(mod);
return mod;
}
@ -1165,10 +1159,12 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
d = PyModule_GetDict(m);
l = PyList_New(0);
if (l == NULL) {
Py_DECREF(m);
goto err_return;
}
err = PyDict_SetItemString(d, "__path__", l);
Py_DECREF(l);
Py_DECREF(m);
if (err != 0)
goto err_return;
}
@ -1177,6 +1173,7 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
goto err_return;
}
m = exec_code_in_module(tstate, name, d, co);
Py_DECREF(d);
if (m == NULL) {
goto err_return;
}
@ -1875,7 +1872,6 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
{
PyThreadState *tstate = _PyThreadState_GET();
int ret;
PyObject *m;
ret = PyImport_ImportFrozenModuleObject(name);
if (ret < 0)
@ -1883,9 +1879,7 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
if (ret == 0) {
Py_RETURN_NONE;
}
m = import_add_module(tstate, name);
Py_XINCREF(m);
return m;
return import_add_module(tstate, name);
}
/*[clinic input]
@ -2009,11 +2003,11 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
return NULL;
}
mod = _PyImport_FindExtensionObject(name, path);
PyThreadState *tstate = _PyThreadState_GET();
mod = import_find_extension(tstate, name, path);
if (mod != NULL || PyErr_Occurred()) {
Py_DECREF(name);
Py_DECREF(path);
Py_XINCREF(mod);
return mod;
}