Skip to content

Commit 648a32b

Browse files
bpo-42412: Fix possible leaks and check arguments in PyType_FromModuleAndSpec() (GH-23410)
* There were leaks if Py_tp_bases is used more than once or if some call is failed before setting tp_bases. * There was a crash if the bases argument or the Py_tp_bases slot is not a tuple. * The documentation was not accurate. (cherry picked from commit 1db7639) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent 97136d7 commit 648a32b

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

Doc/c-api/type.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ The following functions and structs are used to create
124124
If *bases* is a tuple, the created heap type contains all types contained
125125
in it as base types.
126126
127-
If *bases* is ``NULL``, the *Py_tp_base* slot is used instead.
127+
If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead.
128+
If that also is ``NULL``, the *Py_tp_base* slot is used instead.
128129
If that also is ``NULL``, the new type derives from :class:`object`.
129130
130131
This function calls :c:func:`PyType_Ready` on the new type.
@@ -194,7 +195,8 @@ The following functions and structs are used to create
194195
* :c:member:`~PyBufferProcs.bf_getbuffer`
195196
* :c:member:`~PyBufferProcs.bf_releasebuffer`
196197
197-
Setting :c:data:`Py_tp_bases` may be problematic on some platforms.
198+
Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be
199+
problematic on some platforms.
198200
To avoid issues, use the *bases* argument of
199201
:py:func:`PyType_FromSpecWithBases` instead.
200202

Objects/typeobject.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2894,26 +2894,40 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
28942894
base = slot->pfunc;
28952895
else if (slot->slot == Py_tp_bases) {
28962896
bases = slot->pfunc;
2897-
Py_INCREF(bases);
28982897
}
28992898
}
2900-
if (!bases)
2899+
if (!bases) {
29012900
bases = PyTuple_Pack(1, base);
2902-
if (!bases)
2901+
if (!bases)
2902+
goto fail;
2903+
}
2904+
else if (!PyTuple_Check(bases)) {
2905+
PyErr_SetString(PyExc_SystemError, "Py_tp_bases is not a tuple");
29032906
goto fail;
2907+
}
2908+
else {
2909+
Py_INCREF(bases);
2910+
}
29042911
}
2905-
else
2912+
else if (!PyTuple_Check(bases)) {
2913+
PyErr_SetString(PyExc_SystemError, "bases is not a tuple");
2914+
goto fail;
2915+
}
2916+
else {
29062917
Py_INCREF(bases);
2918+
}
29072919

29082920
/* Calculate best base, and check that all bases are type objects */
29092921
base = best_base(bases);
29102922
if (base == NULL) {
2923+
Py_DECREF(bases);
29112924
goto fail;
29122925
}
29132926
if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
29142927
PyErr_Format(PyExc_TypeError,
29152928
"type '%.100s' is not an acceptable base type",
29162929
base->tp_name);
2930+
Py_DECREF(bases);
29172931
goto fail;
29182932
}
29192933

@@ -2925,7 +2939,6 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
29252939
type->tp_as_buffer = &res->as_buffer;
29262940
/* Set tp_base and tp_bases */
29272941
type->tp_bases = bases;
2928-
bases = NULL;
29292942
Py_INCREF(base);
29302943
type->tp_base = base;
29312944

0 commit comments

Comments
 (0)