From ec18362f6a7fdc02f9f982872fc1006bca31627d Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 4 May 2021 16:07:13 +0200 Subject: [3.9] bpo-42083: Allow NULL doc in PyStructSequence_NewType (#25896) (cherry picked from commit 2f5baa17504feb9a7613bac32fdceed4894434de) Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> --- .../C API/2021-05-04-15-13-31.bpo-42083.ekXnbR.rst | 2 ++ Modules/_testcapimodule.c | 21 +++++++++++++++++++++ Objects/structseq.c | 17 +++++++++++------ 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2021-05-04-15-13-31.bpo-42083.ekXnbR.rst diff --git a/Misc/NEWS.d/next/C API/2021-05-04-15-13-31.bpo-42083.ekXnbR.rst b/Misc/NEWS.d/next/C API/2021-05-04-15-13-31.bpo-42083.ekXnbR.rst new file mode 100644 index 0000000..e83bab9 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2021-05-04-15-13-31.bpo-42083.ekXnbR.rst @@ -0,0 +1,2 @@ +Fix crash in :c:func:`PyStructSequence_NewType` when passed ``NULL`` in the +documentation string slot. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 54c1e62..f4e04e7 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3732,6 +3732,25 @@ test_structseq_newtype_doesnt_leak(PyObject *Py_UNUSED(self), } 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)) { PyObject *obj = PyLong_FromLong(0); @@ -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}, diff --git a/Objects/structseq.c b/Objects/structseq.c index b17b1f9..5a493c9 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -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 */ -- cgit v0.12