summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Misc/NEWS.d/next/C API/2021-05-04-15-13-31.bpo-42083.ekXnbR.rst2
-rw-r--r--Modules/_testcapimodule.c21
-rw-r--r--Objects/structseq.c17
3 files changed, 34 insertions, 6 deletions
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 */