Skip to content

Commit d153eb8

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. (cherry picked from commit 1db7639) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 713b4bb commit d153eb8

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
@@ -155,7 +155,8 @@ The following functions and structs are used to create
155155
If *bases* is a tuple, the created heap type contains all types contained
156156
in it as base types.
157157
158-
If *bases* is ``NULL``, the *Py_tp_base* slot is used instead.
158+
If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead.
159+
If that also is ``NULL``, the *Py_tp_base* slot is used instead.
159160
If that also is ``NULL``, the new type derives from :class:`object`.
160161
161162
The *module* argument can be used to record the module in which the new
@@ -247,7 +248,8 @@ The following functions and structs are used to create
247248
* :c:member:`~PyBufferProcs.bf_getbuffer`
248249
* :c:member:`~PyBufferProcs.bf_releasebuffer`
249250
250-
Setting :c:data:`Py_tp_bases` may be problematic on some platforms.
251+
Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be
252+
problematic on some platforms.
251253
To avoid issues, use the *bases* argument of
252254
:py:func:`PyType_FromSpecWithBases` instead.
253255

Objects/typeobject.c

+18-5
Original file line numberDiff line numberDiff line change
@@ -2951,26 +2951,40 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
29512951
base = slot->pfunc;
29522952
else if (slot->slot == Py_tp_bases) {
29532953
bases = slot->pfunc;
2954-
Py_INCREF(bases);
29552954
}
29562955
}
2957-
if (!bases)
2956+
if (!bases) {
29582957
bases = PyTuple_Pack(1, base);
2959-
if (!bases)
2958+
if (!bases)
2959+
goto fail;
2960+
}
2961+
else if (!PyTuple_Check(bases)) {
2962+
PyErr_SetString(PyExc_SystemError, "Py_tp_bases is not a tuple");
29602963
goto fail;
2964+
}
2965+
else {
2966+
Py_INCREF(bases);
2967+
}
29612968
}
2962-
else
2969+
else if (!PyTuple_Check(bases)) {
2970+
PyErr_SetString(PyExc_SystemError, "bases is not a tuple");
2971+
goto fail;
2972+
}
2973+
else {
29632974
Py_INCREF(bases);
2975+
}
29642976

29652977
/* Calculate best base, and check that all bases are type objects */
29662978
base = best_base(bases);
29672979
if (base == NULL) {
2980+
Py_DECREF(bases);
29682981
goto fail;
29692982
}
29702983
if (!_PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
29712984
PyErr_Format(PyExc_TypeError,
29722985
"type '%.100s' is not an acceptable base type",
29732986
base->tp_name);
2987+
Py_DECREF(bases);
29742988
goto fail;
29752989
}
29762990

@@ -2982,7 +2996,6 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
29822996
type->tp_as_buffer = &res->as_buffer;
29832997
/* Set tp_base and tp_bases */
29842998
type->tp_bases = bases;
2985-
bases = NULL;
29862999
Py_INCREF(base);
29873000
type->tp_base = base;
29883001

0 commit comments

Comments
 (0)