Skip to content

[3.8] bpo-42412: Fix possible leaks and check arguments in PyType_FromModuleAndSpec() (GH-23410) #23440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Doc/c-api/type.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.

Expand Down
23 changes: 18 additions & 5 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;

Expand Down