mirror of
https://github.com/python/cpython.git
synced 2025-09-18 14:40:43 +00:00
bpo-41994: Fix refcount issues in Python/import.c (GH-22632)
https://bugs.python.org/issue41994
This commit is contained in:
parent
11d13e83ab
commit
4db8988420
4 changed files with 51 additions and 63 deletions
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed possible leak in ``import`` when ``sys.modules`` is not a ``dict``.
|
104
Python/import.c
104
Python/import.c
|
@ -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,11 +522,15 @@ 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)
|
||||||
return NULL;
|
return 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,12 +953,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue