From 648a32b12ec676036ae4115747d458fb6f379d74 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Sat, 21 Nov 2020 02:39:23 -0800 Subject: 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 1db76394ea79030aa4ed5349c950f6c6da51450f) Co-authored-by: Serhiy Storchaka --- Doc/c-api/type.rst | 6 ++++-- Objects/typeobject.c | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index dcdec53..2a6d618 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -124,7 +124,8 @@ The following functions and structs are used to create If *bases* is a tuple, the created heap type contains all types contained in it as base types. - If *bases* is ``NULL``, the *Py_tp_base* slot is used instead. + If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead. + If that also is ``NULL``, the *Py_tp_base* slot is used instead. If that also is ``NULL``, the new type derives from :class:`object`. This function calls :c:func:`PyType_Ready` on the new type. @@ -194,7 +195,8 @@ The following functions and structs are used to create * :c:member:`~PyBufferProcs.bf_getbuffer` * :c:member:`~PyBufferProcs.bf_releasebuffer` - Setting :c:data:`Py_tp_bases` may be problematic on some platforms. + Setting :c:data:`Py_tp_bases` or :c:data:`Py_tp_base` may be + problematic on some platforms. To avoid issues, use the *bases* argument of :py:func:`PyType_FromSpecWithBases` instead. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 21b1360..6fbeac2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2894,26 +2894,40 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) base = slot->pfunc; else if (slot->slot == Py_tp_bases) { bases = slot->pfunc; - Py_INCREF(bases); } } - if (!bases) + if (!bases) { bases = PyTuple_Pack(1, base); - if (!bases) + if (!bases) + goto fail; + } + else if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, "Py_tp_bases is not a tuple"); goto fail; + } + else { + Py_INCREF(bases); + } } - else + else if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_SystemError, "bases is not a tuple"); + goto fail; + } + else { Py_INCREF(bases); + } /* Calculate best base, and check that all bases are type objects */ base = best_base(bases); if (base == NULL) { + Py_DECREF(bases); goto fail; } if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) { PyErr_Format(PyExc_TypeError, "type '%.100s' is not an acceptable base type", base->tp_name); + Py_DECREF(bases); goto fail; } @@ -2925,7 +2939,6 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) type->tp_as_buffer = &res->as_buffer; /* Set tp_base and tp_bases */ type->tp_bases = bases; - bases = NULL; Py_INCREF(base); type->tp_base = base; -- cgit v0.12