Skip to content

bpo-41994: Fix refcount issues in Python/import.c #22632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 12, 2021
2 changes: 0 additions & 2 deletions Include/cpython/import.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
5 changes: 0 additions & 5 deletions Include/internal/pycore_import.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed possible leak in ``import`` when ``sys.modules`` is not a ``dict``.
106 changes: 50 additions & 56 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -606,14 +590,14 @@ 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;
if (PyObject_SetItem(modules, name, m) != 0) {
Py_DECREF(m);
return NULL;
}
Py_DECREF(m); /* Yes, it still exists, in modules! */

return m;
}
Expand All @@ -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 */
}


Expand Down Expand Up @@ -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)
Expand All @@ -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 *
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -1875,17 +1872,14 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
{
PyThreadState *tstate = _PyThreadState_GET();
int ret;
PyObject *m;

ret = PyImport_ImportFrozenModuleObject(name);
if (ret < 0)
return NULL;
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]
Expand Down Expand Up @@ -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;
}

Expand Down