[3.9] bpo-42083: Allow NULL doc in PyStructSequence_NewType (#25896)

(cherry picked from commit 2f5baa1750)

Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com>
This commit is contained in:
Petr Viktorin 2021-05-04 16:07:13 +02:00 committed by GitHub
parent 4b90c8f176
commit ec18362f6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 6 deletions

View file

@ -0,0 +1,2 @@
Fix crash in :c:func:`PyStructSequence_NewType` when passed ``NULL`` in the
documentation string slot.

View file

@ -3731,6 +3731,25 @@ test_structseq_newtype_doesnt_leak(PyObject *Py_UNUSED(self),
Py_RETURN_NONE;
}
static PyObject *
test_structseq_newtype_null_descr_doc(PyObject *Py_UNUSED(self),
PyObject *Py_UNUSED(args))
{
PyStructSequence_Field descr_fields[1] = {
(PyStructSequence_Field){NULL, NULL}
};
// Test specifically for NULL .doc field.
PyStructSequence_Desc descr = {"_testcapi.test_descr", NULL, &descr_fields[0], 0};
PyTypeObject* structseq_type = PyStructSequence_NewType(&descr);
assert(structseq_type != NULL);
assert(PyType_Check(structseq_type));
assert(PyType_FastSubclass(structseq_type, Py_TPFLAGS_TUPLE_SUBCLASS));
Py_DECREF(structseq_type);
Py_RETURN_NONE;
}
static PyObject *
test_incref_decref_API(PyObject *ob, PyObject *Py_UNUSED(ignored))
{
@ -5335,6 +5354,8 @@ static PyMethodDef TestMethods[] = {
{"test_decref_doesnt_leak", test_decref_doesnt_leak, METH_NOARGS},
{"test_structseq_newtype_doesnt_leak",
test_structseq_newtype_doesnt_leak, METH_NOARGS},
{"test_structseq_newtype_null_descr_doc",
test_structseq_newtype_null_descr_doc, METH_NOARGS},
{"test_incref_decref_API", test_incref_decref_API, METH_NOARGS},
{"test_long_and_overflow", test_long_and_overflow, METH_NOARGS},
{"test_long_as_double", test_long_as_double, METH_NOARGS},

View file

@ -467,12 +467,17 @@ PyStructSequence_NewType(PyStructSequence_Desc *desc)
/* Initialize Slots */
slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc};
slots[1] = (PyType_Slot){Py_tp_repr, (reprfunc)structseq_repr};
slots[2] = (PyType_Slot){Py_tp_doc, (void *)desc->doc};
slots[3] = (PyType_Slot){Py_tp_methods, structseq_methods};
slots[4] = (PyType_Slot){Py_tp_new, structseq_new};
slots[5] = (PyType_Slot){Py_tp_members, members};
slots[6] = (PyType_Slot){Py_tp_traverse, (traverseproc)structseq_traverse};
slots[7] = (PyType_Slot){0, 0};
slots[2] = (PyType_Slot){Py_tp_methods, structseq_methods};
slots[3] = (PyType_Slot){Py_tp_new, structseq_new};
slots[4] = (PyType_Slot){Py_tp_members, members};
slots[5] = (PyType_Slot){Py_tp_traverse, (traverseproc)structseq_traverse};
if (desc->doc) {
slots[6] = (PyType_Slot){Py_tp_doc, (void *)desc->doc};
slots[7] = (PyType_Slot){0, 0};
}
else {
slots[6] = (PyType_Slot){0, 0};
}
/* Initialize Spec */
/* The name in this PyType_Spec is statically allocated so it is */