Skip to content

Commit 4db8988

Browse files
bpo-41994: Fix refcount issues in Python/import.c (GH-22632)
https://bugs.python.org/issue41994
1 parent 11d13e8 commit 4db8988

File tree

4 files changed

+51
-63
lines changed

4 files changed

+51
-63
lines changed

Include/cpython/import.h

-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module);
1313
PyAPI_FUNC(void) _PyImport_AcquireLock(void);
1414
PyAPI_FUNC(int) _PyImport_ReleaseLock(void);
1515

16-
PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObject(PyObject *, PyObject *);
17-
1816
PyAPI_FUNC(int) _PyImport_FixupBuiltin(
1917
PyObject *mod,
2018
const char *name, /* UTF-8 encoded string */

Include/internal/pycore_import.h

-5
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
extern "C" {
66
#endif
77

8-
PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin(
9-
PyThreadState *tstate,
10-
const char *name /* UTF-8 encoded string */
11-
);
12-
138
#ifdef HAVE_FORK
149
extern PyStatus _PyImport_ReInitLock(void);
1510
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed possible leak in ``import`` when ``sys.modules`` is not a ``dict``.

Python/import.c

+50-56
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ PyImport_GetMagicTag(void)
409409
modules. A copy of the module's dictionary is stored by calling
410410
_PyImport_FixupExtensionObject() immediately after the module initialization
411411
function succeeds. A copy can be retrieved from there by calling
412-
_PyImport_FindExtensionObject().
412+
import_find_extension().
413413
414414
Modules which do support multiple initialization set their m_size
415415
field to a non-negative number (indicating the size of the
@@ -522,10 +522,14 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
522522
if (mod == NULL)
523523
return NULL;
524524
mdict = PyModule_GetDict(mod);
525-
if (mdict == NULL)
525+
if (mdict == NULL) {
526+
Py_DECREF(mod);
526527
return NULL;
527-
if (PyDict_Update(mdict, def->m_base.m_copy))
528+
}
529+
if (PyDict_Update(mdict, def->m_base.m_copy)) {
530+
Py_DECREF(mod);
528531
return NULL;
532+
}
529533
}
530534
else {
531535
if (def->m_base.m_init == NULL)
@@ -537,10 +541,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
537541
Py_DECREF(mod);
538542
return NULL;
539543
}
540-
Py_DECREF(mod);
541544
}
542545
if (_PyState_AddModule(tstate, mod, def) < 0) {
543546
PyMapping_DelItem(modules, name);
547+
Py_DECREF(mod);
544548
return NULL;
545549
}
546550

@@ -552,31 +556,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
552556
return mod;
553557
}
554558

555-
PyObject *
556-
_PyImport_FindExtensionObject(PyObject *name, PyObject *filename)
557-
{
558-
PyThreadState *tstate = _PyThreadState_GET();
559-
return import_find_extension(tstate, name, filename);
560-
}
561-
562-
563-
PyObject *
564-
_PyImport_FindBuiltin(PyThreadState *tstate, const char *name)
565-
{
566-
PyObject *res, *nameobj;
567-
nameobj = PyUnicode_InternFromString(name);
568-
if (nameobj == NULL)
569-
return NULL;
570-
res = import_find_extension(tstate, nameobj, nameobj);
571-
Py_DECREF(nameobj);
572-
return res;
573-
}
574559

575560
/* Get the module object corresponding to a module name.
576561
First check the modules dictionary if there's one there,
577-
if not, create a new one and insert it in the modules dictionary.
578-
Because the former action is most common, THIS DOES NOT RETURN A
579-
'NEW' REFERENCE! */
562+
if not, create a new one and insert it in the modules dictionary. */
580563

581564
static PyObject *
582565
import_add_module(PyThreadState *tstate, PyObject *name)
@@ -591,6 +574,7 @@ import_add_module(PyThreadState *tstate, PyObject *name)
591574
PyObject *m;
592575
if (PyDict_CheckExact(modules)) {
593576
m = PyDict_GetItemWithError(modules, name);
577+
Py_XINCREF(m);
594578
}
595579
else {
596580
m = PyObject_GetItem(modules, name);
@@ -606,14 +590,14 @@ import_add_module(PyThreadState *tstate, PyObject *name)
606590
if (m != NULL && PyModule_Check(m)) {
607591
return m;
608592
}
593+
Py_XDECREF(m);
609594
m = PyModule_NewObject(name);
610595
if (m == NULL)
611596
return NULL;
612597
if (PyObject_SetItem(modules, name, m) != 0) {
613598
Py_DECREF(m);
614599
return NULL;
615600
}
616-
Py_DECREF(m); /* Yes, it still exists, in modules! */
617601

618602
return m;
619603
}
@@ -622,7 +606,17 @@ PyObject *
622606
PyImport_AddModuleObject(PyObject *name)
623607
{
624608
PyThreadState *tstate = _PyThreadState_GET();
625-
return import_add_module(tstate, name);
609+
PyObject *mod = import_add_module(tstate, name);
610+
if (mod) {
611+
PyObject *ref = PyWeakref_NewRef(mod, NULL);
612+
Py_DECREF(mod);
613+
if (ref == NULL) {
614+
return NULL;
615+
}
616+
mod = PyWeakref_GetObject(ref);
617+
Py_DECREF(ref);
618+
}
619+
return mod; /* borrowed reference */
626620
}
627621

628622

@@ -747,7 +741,7 @@ static PyObject *
747741
module_dict_for_exec(PyThreadState *tstate, PyObject *name)
748742
{
749743
_Py_IDENTIFIER(__builtins__);
750-
PyObject *m, *d = NULL;
744+
PyObject *m, *d;
751745

752746
m = import_add_module(tstate, name);
753747
if (m == NULL)
@@ -762,10 +756,13 @@ module_dict_for_exec(PyThreadState *tstate, PyObject *name)
762756
}
763757
if (r < 0) {
764758
remove_module(tstate, name);
759+
Py_DECREF(m);
765760
return NULL;
766761
}
767762

768-
return d; /* Return a borrowed reference. */
763+
Py_INCREF(d);
764+
Py_DECREF(m);
765+
return d;
769766
}
770767

771768
static PyObject *
@@ -809,8 +806,10 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
809806
}
810807
external = PyObject_GetAttrString(tstate->interp->importlib,
811808
"_bootstrap_external");
812-
if (external == NULL)
809+
if (external == NULL) {
810+
Py_DECREF(d);
813811
return NULL;
812+
}
814813
res = _PyObject_CallMethodIdObjArgs(external,
815814
&PyId__fix_up_module,
816815
d, name, pathname, cpathname, NULL);
@@ -819,6 +818,7 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
819818
Py_DECREF(res);
820819
res = exec_code_in_module(tstate, name, d, co);
821820
}
821+
Py_DECREF(d);
822822
return res;
823823
}
824824

@@ -912,8 +912,7 @@ is_builtin(PyObject *name)
912912
that can handle the path item. Return None if no hook could;
913913
this tells our caller that the path based finder could not find
914914
a finder for this path item. Cache the result in
915-
path_importer_cache.
916-
Returns a borrowed reference. */
915+
path_importer_cache. */
917916

918917
static PyObject *
919918
get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache,
@@ -931,8 +930,10 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache,
931930
return NULL; /* Shouldn't happen */
932931

933932
importer = PyDict_GetItemWithError(path_importer_cache, p);
934-
if (importer != NULL || _PyErr_Occurred(tstate))
933+
if (importer != NULL || _PyErr_Occurred(tstate)) {
934+
Py_XINCREF(importer);
935935
return importer;
936+
}
936937

937938
/* set path_importer_cache[p] to None to avoid recursion */
938939
if (PyDict_SetItem(path_importer_cache, p, Py_None) != 0)
@@ -952,13 +953,11 @@ get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache,
952953
_PyErr_Clear(tstate);
953954
}
954955
if (importer == NULL) {
955-
return Py_None;
956+
Py_RETURN_NONE;
956957
}
957-
if (importer != NULL) {
958-
int err = PyDict_SetItem(path_importer_cache, p, importer);
958+
if (PyDict_SetItem(path_importer_cache, p, importer) < 0) {
959959
Py_DECREF(importer);
960-
if (err != 0)
961-
return NULL;
960+
return NULL;
962961
}
963962
return importer;
964963
}
@@ -967,24 +966,19 @@ PyObject *
967966
PyImport_GetImporter(PyObject *path)
968967
{
969968
PyThreadState *tstate = _PyThreadState_GET();
970-
PyObject *importer=NULL, *path_importer_cache=NULL, *path_hooks=NULL;
971-
972-
path_importer_cache = PySys_GetObject("path_importer_cache");
973-
path_hooks = PySys_GetObject("path_hooks");
974-
if (path_importer_cache != NULL && path_hooks != NULL) {
975-
importer = get_path_importer(tstate, path_importer_cache,
976-
path_hooks, path);
969+
PyObject *path_importer_cache = PySys_GetObject("path_importer_cache");
970+
PyObject *path_hooks = PySys_GetObject("path_hooks");
971+
if (path_importer_cache == NULL || path_hooks == NULL) {
972+
return NULL;
977973
}
978-
Py_XINCREF(importer); /* get_path_importer returns a borrowed reference */
979-
return importer;
974+
return get_path_importer(tstate, path_importer_cache, path_hooks, path);
980975
}
981976

982977
static PyObject*
983978
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
984979
{
985-
PyObject *mod = _PyImport_FindExtensionObject(name, name);
980+
PyObject *mod = import_find_extension(tstate, name, name);
986981
if (mod || _PyErr_Occurred(tstate)) {
987-
Py_XINCREF(mod);
988982
return mod;
989983
}
990984

@@ -1165,10 +1159,12 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
11651159
d = PyModule_GetDict(m);
11661160
l = PyList_New(0);
11671161
if (l == NULL) {
1162+
Py_DECREF(m);
11681163
goto err_return;
11691164
}
11701165
err = PyDict_SetItemString(d, "__path__", l);
11711166
Py_DECREF(l);
1167+
Py_DECREF(m);
11721168
if (err != 0)
11731169
goto err_return;
11741170
}
@@ -1177,6 +1173,7 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
11771173
goto err_return;
11781174
}
11791175
m = exec_code_in_module(tstate, name, d, co);
1176+
Py_DECREF(d);
11801177
if (m == NULL) {
11811178
goto err_return;
11821179
}
@@ -1875,17 +1872,14 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
18751872
{
18761873
PyThreadState *tstate = _PyThreadState_GET();
18771874
int ret;
1878-
PyObject *m;
18791875

18801876
ret = PyImport_ImportFrozenModuleObject(name);
18811877
if (ret < 0)
18821878
return NULL;
18831879
if (ret == 0) {
18841880
Py_RETURN_NONE;
18851881
}
1886-
m = import_add_module(tstate, name);
1887-
Py_XINCREF(m);
1888-
return m;
1882+
return import_add_module(tstate, name);
18891883
}
18901884

18911885
/*[clinic input]
@@ -2009,11 +2003,11 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
20092003
return NULL;
20102004
}
20112005

2012-
mod = _PyImport_FindExtensionObject(name, path);
2006+
PyThreadState *tstate = _PyThreadState_GET();
2007+
mod = import_find_extension(tstate, name, path);
20132008
if (mod != NULL || PyErr_Occurred()) {
20142009
Py_DECREF(name);
20152010
Py_DECREF(path);
2016-
Py_XINCREF(mod);
20172011
return mod;
20182012
}
20192013

0 commit comments

Comments
 (0)