Skip to content

Commit 1db7639

Browse files
bpo-42412: Fix possible leaks and check arguments in PyType_FromModuleAndSpec() (pythonGH-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.
1 parent 01a202a commit 1db7639

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

Doc/c-api/type.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ The following functions and structs are used to create
157157
If *bases* is a tuple, the created heap type contains all types contained
158158
in it as base types.
159159
160-
If *bases* is ``NULL``, the *Py_tp_base* slot is used instead.
160+
If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead.
161+
If that also is ``NULL``, the *Py_tp_base* slot is used instead.
161162
If that also is ``NULL``, the new type derives from :class:`object`.
162163
163164
The *module* argument can be used to record the module in which the new
@@ -253,7 +254,8 @@ The following functions and structs are used to create
253254
* :c:member:`~PyBufferProcs.bf_getbuffer`
254255
* :c:member:`~PyBufferProcs.bf_releasebuffer`
255256
256-
Setting :c:data:`Py_tp_bases` may be problematic on some platforms.
257+
Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be
258+
problematic on some platforms.
257259
To avoid issues, use the *bases* argument of
258260
:py:func:`PyType_FromSpecWithBases` instead.
259261

Objects/typeobject.c

+18-5
Original file line numberDiff line numberDiff line change
@@ -2977,26 +2977,40 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
29772977
base = slot->pfunc;
29782978
else if (slot->slot == Py_tp_bases) {
29792979
bases = slot->pfunc;
2980-
Py_INCREF(bases);
29812980
}
29822981
}
2983-
if (!bases)
2982+
if (!bases) {
29842983
bases = PyTuple_Pack(1, base);
2985-
if (!bases)
2984+
if (!bases)
2985+
goto fail;
2986+
}
2987+
else if (!PyTuple_Check(bases)) {
2988+
PyErr_SetString(PyExc_SystemError, "Py_tp_bases is not a tuple");
29862989
goto fail;
2990+
}
2991+
else {
2992+
Py_INCREF(bases);
2993+
}
29872994
}
2988-
else
2995+
else if (!PyTuple_Check(bases)) {
2996+
PyErr_SetString(PyExc_SystemError, "bases is not a tuple");
2997+
goto fail;
2998+
}
2999+
else {
29893000
Py_INCREF(bases);
3001+
}
29903002

29913003
/* Calculate best base, and check that all bases are type objects */
29923004
base = best_base(bases);
29933005
if (base == NULL) {
3006+
Py_DECREF(bases);
29943007
goto fail;
29953008
}
29963009
if (!_PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
29973010
PyErr_Format(PyExc_TypeError,
29983011
"type '%.100s' is not an acceptable base type",
29993012
base->tp_name);
3013+
Py_DECREF(bases);
30003014
goto fail;
30013015
}
30023016

@@ -3008,7 +3022,6 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
30083022
type->tp_as_buffer = &res->as_buffer;
30093023
/* Set tp_base and tp_bases */
30103024
type->tp_bases = bases;
3011-
bases = NULL;
30123025
Py_INCREF(base);
30133026
type->tp_base = base;
30143027

0 commit comments

Comments
 (0)