with self.assertRaisesRegex(TypeError, msg):
t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclassCustomNew)
+ def test_pytype_fromspec_with_repeated_slots(self):
+ for variant in range(2):
+ with self.subTest(variant=variant):
+ with self.assertRaises(SystemError):
+ _testcapi.create_type_from_repeated_slots(variant)
+
def test_pynumber_tobase(self):
from _testcapi import pynumber_tobase
self.assertEqual(pynumber_tobase(123, 2), '0b1111011')
return result;
}
+PyType_Slot repeated_doc_slots[] = {
+ {Py_tp_doc, "A class used for testsĀ·"},
+ {Py_tp_doc, "A class used for tests"},
+ {0, 0},
+};
+
+PyType_Spec repeated_doc_slots_spec = {
+ .name = "RepeatedDocSlotClass",
+ .basicsize = sizeof(PyObject),
+ .slots = repeated_doc_slots,
+};
+
+typedef struct {
+ PyObject_HEAD
+ int data;
+} HeapCTypeWithDataObject;
+
+
+static struct PyMemberDef members_to_repeat[] = {
+ {"T_INT", T_INT, offsetof(HeapCTypeWithDataObject, data), 0, NULL},
+ {NULL}
+};
+
+PyType_Slot repeated_members_slots[] = {
+ {Py_tp_members, members_to_repeat},
+ {Py_tp_members, members_to_repeat},
+ {0, 0},
+};
+
+PyType_Spec repeated_members_slots_spec = {
+ .name = "RepeatedMembersSlotClass",
+ .basicsize = sizeof(HeapCTypeWithDataObject),
+ .slots = repeated_members_slots,
+};
+
+static PyObject *
+create_type_from_repeated_slots(PyObject *self, PyObject *variant_obj)
+{
+ PyObject *class = NULL;
+ int variant = PyLong_AsLong(variant_obj);
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ switch (variant) {
+ case 0:
+ class = PyType_FromSpec(&repeated_doc_slots_spec);
+ break;
+ case 1:
+ class = PyType_FromSpec(&repeated_members_slots_spec);
+ break;
+ default:
+ PyErr_SetString(PyExc_ValueError, "bad test variant");
+ break;
+ }
+ return class;
+}
+
static PyObject *
test_get_type_qualname(PyObject *self, PyObject *Py_UNUSED(ignored))
{"test_get_type_name", test_get_type_name, METH_NOARGS},
{"test_get_type_qualname", test_get_type_qualname, METH_NOARGS},
{"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS},
+ {"create_type_from_repeated_slots",
+ create_type_from_repeated_slots, METH_O},
{"test_from_spec_metatype_inheritance", test_from_spec_metatype_inheritance,
METH_NOARGS},
{"test_from_spec_invalid_metatype_inheritance",
int r;
const PyType_Slot *slot;
- Py_ssize_t nmembers, weaklistoffset, dictoffset, vectorcalloffset;
+ Py_ssize_t nmembers = 0;
+ Py_ssize_t weaklistoffset, dictoffset, vectorcalloffset;
char *res_start;
short slot_offset, subslot_offset;
nmembers = weaklistoffset = dictoffset = vectorcalloffset = 0;
for (slot = spec->slots; slot->slot; slot++) {
if (slot->slot == Py_tp_members) {
- nmembers = 0;
+ if (nmembers != 0) {
+ PyErr_SetString(
+ PyExc_SystemError,
+ "Multiple Py_tp_members slots are not supported.");
+ return NULL;
+ }
for (const PyMemberDef *memb = slot->pfunc; memb->name != NULL; memb++) {
nmembers++;
if (strcmp(memb->name, "__weaklistoffset__") == 0) {
else if (slot->slot == Py_tp_doc) {
/* For the docstring slot, which usually points to a static string
literal, we need to make a copy */
+ if (type->tp_doc != NULL) {
+ PyErr_SetString(
+ PyExc_SystemError,
+ "Multiple Py_tp_doc slots are not supported.");
+ return NULL;
+ }
if (slot->pfunc == NULL) {
type->tp_doc = NULL;
continue;