Skip to content

Commit 25ba819

Browse files
bpo-41994: Fix refcount issues in Python/import.c
1 parent a427593 commit 25ba819

File tree

4 files changed

+48
-46
lines changed

4 files changed

+48
-46
lines changed

Include/cpython/import.h

Lines changed: 0 additions & 2 deletions
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

Lines changed: 0 additions & 5 deletions
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
Lines changed: 1 addition & 0 deletions
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

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ PyImport_GetMagicTag(void)
672672
modules. A copy of the module's dictionary is stored by calling
673673
_PyImport_FixupExtensionObject() immediately after the module initialization
674674
function succeeds. A copy can be retrieved from there by calling
675-
_PyImport_FindExtensionObject().
675+
import_find_extension().
676676
677677
Modules which do support multiple initialization set their m_size
678678
field to a non-negative number (indicating the size of the
@@ -785,10 +785,14 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
785785
if (mod == NULL)
786786
return NULL;
787787
mdict = PyModule_GetDict(mod);
788-
if (mdict == NULL)
788+
if (mdict == NULL) {
789+
Py_DECREF(mod);
789790
return NULL;
790-
if (PyDict_Update(mdict, def->m_base.m_copy))
791+
}
792+
if (PyDict_Update(mdict, def->m_base.m_copy)) {
793+
Py_DECREF(mod);
791794
return NULL;
795+
}
792796
}
793797
else {
794798
if (def->m_base.m_init == NULL)
@@ -800,10 +804,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
800804
Py_DECREF(mod);
801805
return NULL;
802806
}
803-
Py_DECREF(mod);
804807
}
805808
if (_PyState_AddModule(tstate, mod, def) < 0) {
806809
PyMapping_DelItem(modules, name);
810+
Py_DECREF(mod);
807811
return NULL;
808812
}
809813

@@ -815,31 +819,10 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
815819
return mod;
816820
}
817821

818-
PyObject *
819-
_PyImport_FindExtensionObject(PyObject *name, PyObject *filename)
820-
{
821-
PyThreadState *tstate = _PyThreadState_GET();
822-
return import_find_extension(tstate, name, filename);
823-
}
824-
825-
826-
PyObject *
827-
_PyImport_FindBuiltin(PyThreadState *tstate, const char *name)
828-
{
829-
PyObject *res, *nameobj;
830-
nameobj = PyUnicode_InternFromString(name);
831-
if (nameobj == NULL)
832-
return NULL;
833-
res = import_find_extension(tstate, nameobj, nameobj);
834-
Py_DECREF(nameobj);
835-
return res;
836-
}
837822

838823
/* Get the module object corresponding to a module name.
839824
First check the modules dictionary if there's one there,
840-
if not, create a new one and insert it in the modules dictionary.
841-
Because the former action is most common, THIS DOES NOT RETURN A
842-
'NEW' REFERENCE! */
825+
if not, create a new one and insert it in the modules dictionary. */
843826

844827
static PyObject *
845828
import_add_module(PyThreadState *tstate, PyObject *name)
@@ -854,6 +837,7 @@ import_add_module(PyThreadState *tstate, PyObject *name)
854837
PyObject *m;
855838
if (PyDict_CheckExact(modules)) {
856839
m = PyDict_GetItemWithError(modules, name);
840+
Py_XINCREF(m);
857841
}
858842
else {
859843
m = PyObject_GetItem(modules, name);
@@ -869,14 +853,14 @@ import_add_module(PyThreadState *tstate, PyObject *name)
869853
if (m != NULL && PyModule_Check(m)) {
870854
return m;
871855
}
856+
Py_XDECREF(m);
872857
m = PyModule_NewObject(name);
873858
if (m == NULL)
874859
return NULL;
875860
if (PyObject_SetItem(modules, name, m) != 0) {
876861
Py_DECREF(m);
877862
return NULL;
878863
}
879-
Py_DECREF(m); /* Yes, it still exists, in modules! */
880864

881865
return m;
882866
}
@@ -885,7 +869,25 @@ PyObject *
885869
PyImport_AddModuleObject(PyObject *name)
886870
{
887871
PyThreadState *tstate = _PyThreadState_GET();
888-
return import_add_module(tstate, name);
872+
PyObject *mod = import_add_module(tstate, name);
873+
if (mod) {
874+
if (Py_REFCNT(mod) == 1) {
875+
/* This check does not preven an undefined behavior in the
876+
* following code, because the module can have references
877+
* to itself. */
878+
PyErr_SetString(PyExc_RuntimeError, "Unexpected zero reference count");
879+
Py_DECREF(mod);
880+
return NULL;
881+
}
882+
Py_DECREF(mod);
883+
if (Py_REFCNT(mod) == 0) {
884+
/* Strictly speaking, this is an undefined behafior, and
885+
* the above check can crash. */
886+
PyErr_SetString(PyExc_RuntimeError, "Unexpected zero reference count");
887+
return NULL;
888+
}
889+
}
890+
return mod; /* borrowed reference */
889891
}
890892

891893

@@ -1007,7 +1009,7 @@ static PyObject *
10071009
module_dict_for_exec(PyThreadState *tstate, PyObject *name)
10081010
{
10091011
_Py_IDENTIFIER(__builtins__);
1010-
PyObject *m, *d = NULL;
1012+
PyObject *m, *d;
10111013

10121014
m = import_add_module(tstate, name);
10131015
if (m == NULL)
@@ -1021,11 +1023,14 @@ module_dict_for_exec(PyThreadState *tstate, PyObject *name)
10211023
PyEval_GetBuiltins()) != 0)
10221024
{
10231025
remove_module(tstate, name);
1026+
Py_DECREF(m);
10241027
return NULL;
10251028
}
10261029
}
10271030

1028-
return d; /* Return a borrowed reference. */
1031+
Py_INCREF(d);
1032+
Py_DECREF(m);
1033+
return d;
10291034
}
10301035

10311036
static PyObject *
@@ -1069,8 +1074,10 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
10691074
}
10701075
external = PyObject_GetAttrString(tstate->interp->importlib,
10711076
"_bootstrap_external");
1072-
if (external == NULL)
1077+
if (external == NULL) {
1078+
Py_DECREF(d);
10731079
return NULL;
1080+
}
10741081
res = _PyObject_CallMethodIdObjArgs(external,
10751082
&PyId__fix_up_module,
10761083
d, name, pathname, cpathname, NULL);
@@ -1079,6 +1086,7 @@ PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname,
10791086
Py_DECREF(res);
10801087
res = exec_code_in_module(tstate, name, d, co);
10811088
}
1089+
Py_DECREF(d);
10821090
return res;
10831091
}
10841092

@@ -1263,10 +1271,9 @@ _imp_create_builtin(PyObject *module, PyObject *spec)
12631271
return NULL;
12641272
}
12651273

1266-
mod = _PyImport_FindExtensionObject(name, name);
1274+
mod = import_find_extension(tstate, name, name);
12671275
if (mod || _PyErr_Occurred(tstate)) {
12681276
Py_DECREF(name);
1269-
Py_XINCREF(mod);
12701277
return mod;
12711278
}
12721279

@@ -1429,10 +1436,12 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
14291436
d = PyModule_GetDict(m);
14301437
l = PyList_New(0);
14311438
if (l == NULL) {
1439+
Py_DECREF(m);
14321440
goto err_return;
14331441
}
14341442
err = PyDict_SetItemString(d, "__path__", l);
14351443
Py_DECREF(l);
1444+
Py_DECREF(m);
14361445
if (err != 0)
14371446
goto err_return;
14381447
}
@@ -1442,10 +1451,12 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
14421451
}
14431452
m = exec_code_in_module(tstate, name, d, co);
14441453
if (m == NULL) {
1454+
Py_DECREF(d);
14451455
goto err_return;
14461456
}
14471457
Py_DECREF(co);
14481458
Py_DECREF(m);
1459+
Py_DECREF(d);
14491460
return 1;
14501461

14511462
err_return:
@@ -2135,17 +2146,14 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
21352146
{
21362147
PyThreadState *tstate = _PyThreadState_GET();
21372148
int ret;
2138-
PyObject *m;
21392149

21402150
ret = PyImport_ImportFrozenModuleObject(name);
21412151
if (ret < 0)
21422152
return NULL;
21432153
if (ret == 0) {
21442154
Py_RETURN_NONE;
21452155
}
2146-
m = import_add_module(tstate, name);
2147-
Py_XINCREF(m);
2148-
return m;
2156+
return import_add_module(tstate, name);
21492157
}
21502158

21512159
/*[clinic input]
@@ -2269,11 +2277,11 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
22692277
return NULL;
22702278
}
22712279

2272-
mod = _PyImport_FindExtensionObject(name, path);
2280+
PyThreadState *tstate = _PyThreadState_GET();
2281+
mod = import_find_extension(tstate, name, path);
22732282
if (mod != NULL || PyErr_Occurred()) {
22742283
Py_DECREF(name);
22752284
Py_DECREF(path);
2276-
Py_XINCREF(mod);
22772285
return mod;
22782286
}
22792287

0 commit comments

Comments
 (0)