1 #include "parts.h"
2 #include "structmember.h" // PyMemberDef
3
4 static struct PyModuleDef *_testcapimodule = NULL; // set at initialization
5
6 /* Tests for heap types (PyType_From*) */
7
8 static PyObject *pytype_fromspec_meta(PyObject* self, PyObject *meta)
9 {
10 if (!PyType_Check(meta)) {
11 PyErr_SetString(
12 PyExc_TypeError,
13 "pytype_fromspec_meta: must be invoked with a type argument!");
14 return NULL;
15 }
16
17 PyType_Slot HeapCTypeViaMetaclass_slots[] = {
18 {0},
19 };
20
21 PyType_Spec HeapCTypeViaMetaclass_spec = {
22 "_testcapi.HeapCTypeViaMetaclass",
23 sizeof(PyObject),
24 0,
25 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
26 HeapCTypeViaMetaclass_slots
27 };
28
29 return PyType_FromMetaclass(
30 (PyTypeObject *) meta, NULL, &HeapCTypeViaMetaclass_spec, NULL);
31 }
32
33
34 static PyType_Slot empty_type_slots[] = {
35 {0, 0},
36 };
37
38 static PyType_Spec MinimalMetaclass_spec = {
39 .name = "_testcapi.MinimalMetaclass",
40 .basicsize = sizeof(PyHeapTypeObject),
41 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
42 .slots = empty_type_slots,
43 };
44
45 static PyType_Spec MinimalType_spec = {
46 .name = "_testcapi.MinimalSpecType",
47 .basicsize = 0, // Updated later
48 .flags = Py_TPFLAGS_DEFAULT,
49 .slots = empty_type_slots,
50 };
51
52
53 static PyObject *
54 test_from_spec_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
55 {
56 PyObject *metaclass = NULL;
57 PyObject *class = NULL;
58 PyObject *new = NULL;
59 PyObject *subclasses = NULL;
60 PyObject *result = NULL;
61 int r;
62
63 metaclass = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
64 if (metaclass == NULL) {
65 goto finally;
66 }
67 class = PyObject_CallFunction(metaclass, "s(){}", "TestClass");
68 if (class == NULL) {
69 goto finally;
70 }
71
72 MinimalType_spec.basicsize = (int)(((PyTypeObject*)class)->tp_basicsize);
73 new = PyType_FromSpecWithBases(&MinimalType_spec, class);
74 if (new == NULL) {
75 goto finally;
76 }
77 if (Py_TYPE(new) != (PyTypeObject*)metaclass) {
78 PyErr_SetString(PyExc_AssertionError,
79 "Metaclass not set properly!");
80 goto finally;
81 }
82
83 /* Assert that __subclasses__ is updated */
84 subclasses = PyObject_CallMethod(class, "__subclasses__", "");
85 if (!subclasses) {
86 goto finally;
87 }
88 r = PySequence_Contains(subclasses, new);
89 if (r < 0) {
90 goto finally;
91 }
92 if (r == 0) {
93 PyErr_SetString(PyExc_AssertionError,
94 "subclasses not set properly!");
95 goto finally;
96 }
97
98 result = Py_NewRef(Py_None);
99
100 finally:
101 Py_XDECREF(metaclass);
102 Py_XDECREF(class);
103 Py_XDECREF(new);
104 Py_XDECREF(subclasses);
105 return result;
106 }
107
108
109 static PyObject *
110 test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED(ignored))
111 {
112 PyObject *metaclass_a = NULL;
113 PyObject *metaclass_b = NULL;
114 PyObject *class_a = NULL;
115 PyObject *class_b = NULL;
116 PyObject *bases = NULL;
117 PyObject *new = NULL;
118 PyObject *meta_error_string = NULL;
119 PyObject *exc = NULL;
120 PyObject *result = NULL;
121 PyObject *message = NULL;
122 PyObject *args = NULL;
123
124 metaclass_a = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
125 if (metaclass_a == NULL) {
126 goto finally;
127 }
128 metaclass_b = PyType_FromSpecWithBases(&MinimalMetaclass_spec, (PyObject*)&PyType_Type);
129 if (metaclass_b == NULL) {
130 goto finally;
131 }
132 class_a = PyObject_CallFunction(metaclass_a, "s(){}", "TestClassA");
133 if (class_a == NULL) {
134 goto finally;
135 }
136
137 class_b = PyObject_CallFunction(metaclass_b, "s(){}", "TestClassB");
138 if (class_b == NULL) {
139 goto finally;
140 }
141
142 bases = PyTuple_Pack(2, class_a, class_b);
143 if (bases == NULL) {
144 goto finally;
145 }
146
147 /*
148 * The following should raise a TypeError due to a MetaClass conflict.
149 */
150 new = PyType_FromSpecWithBases(&MinimalType_spec, bases);
151 if (new != NULL) {
152 PyErr_SetString(PyExc_AssertionError,
153 "MetaType conflict not recognized by PyType_FromSpecWithBases");
154 goto finally;
155 }
156
157 // Assert that the correct exception was raised
158 if (PyErr_ExceptionMatches(PyExc_TypeError)) {
159 exc = PyErr_GetRaisedException();
160 args = PyException_GetArgs(exc);
161 if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) {
162 PyErr_SetString(PyExc_AssertionError,
163 "TypeError args are not a one-tuple");
164 goto finally;
165 }
166 message = Py_NewRef(PyTuple_GET_ITEM(args, 0));
167 meta_error_string = PyUnicode_FromString("metaclass conflict:");
168 if (meta_error_string == NULL) {
169 goto finally;
170 }
171 int res = PyUnicode_Contains(message, meta_error_string);
172 if (res < 0) {
173 goto finally;
174 }
175 if (res == 0) {
176 PyErr_SetString(PyExc_AssertionError,
177 "TypeError did not include expected message.");
178 goto finally;
179 }
180 result = Py_NewRef(Py_None);
181 }
182 finally:
183 Py_XDECREF(metaclass_a);
184 Py_XDECREF(metaclass_b);
185 Py_XDECREF(bases);
186 Py_XDECREF(new);
187 Py_XDECREF(meta_error_string);
188 Py_XDECREF(exc);
189 Py_XDECREF(message);
190 Py_XDECREF(class_a);
191 Py_XDECREF(class_b);
192 Py_XDECREF(args);
193 return result;
194 }
195
196
197 static PyObject *
198 simple_str(PyObject *self) {
199 return PyUnicode_FromString("<test>");
200 }
201
202
203 static PyObject *
204 test_type_from_ephemeral_spec(PyObject *self, PyObject *Py_UNUSED(ignored))
205 {
206 // Test that a heap type can be created from a spec that's later deleted
207 // (along with all its contents).
208 // All necessary data must be copied and held by the class
209 PyType_Spec *spec = NULL;
210 char *name = NULL;
211 char *doc = NULL;
212 PyType_Slot *slots = NULL;
213 PyObject *class = NULL;
214 PyObject *instance = NULL;
215 PyObject *obj = NULL;
216 PyObject *result = NULL;
217
218 /* create a spec (and all its contents) on the heap */
219
220 const char NAME[] = "testcapi._Test";
221 const char DOC[] = "a test class";
222
223 spec = PyMem_New(PyType_Spec, 1);
224 if (spec == NULL) {
225 PyErr_NoMemory();
226 goto finally;
227 }
228 name = PyMem_New(char, sizeof(NAME));
229 if (name == NULL) {
230 PyErr_NoMemory();
231 goto finally;
232 }
233 memcpy(name, NAME, sizeof(NAME));
234
235 doc = PyMem_New(char, sizeof(DOC));
236 if (doc == NULL) {
237 PyErr_NoMemory();
238 goto finally;
239 }
240 memcpy(doc, DOC, sizeof(DOC));
241
242 spec->name = name;
243 spec->basicsize = sizeof(PyObject);
244 spec->itemsize = 0;
245 spec->flags = Py_TPFLAGS_DEFAULT;
246 slots = PyMem_New(PyType_Slot, 3);
247 if (slots == NULL) {
248 PyErr_NoMemory();
249 goto finally;
250 }
251 slots[0].slot = Py_tp_str;
252 slots[0].pfunc = simple_str;
253 slots[1].slot = Py_tp_doc;
254 slots[1].pfunc = doc;
255 slots[2].slot = 0;
256 slots[2].pfunc = NULL;
257 spec->slots = slots;
258
259 /* create the class */
260
261 class = PyType_FromSpec(spec);
262 if (class == NULL) {
263 goto finally;
264 }
265
266 /* deallocate the spec (and all contents) */
267
268 // (Explicitly overwrite memory before freeing,
269 // so bugs show themselves even without the debug allocator's help.)
270 memset(spec, 0xdd, sizeof(PyType_Spec));
271 PyMem_Del(spec);
272 spec = NULL;
273 memset(name, 0xdd, sizeof(NAME));
274 PyMem_Del(name);
275 name = NULL;
276 memset(doc, 0xdd, sizeof(DOC));
277 PyMem_Del(doc);
278 doc = NULL;
279 memset(slots, 0xdd, 3 * sizeof(PyType_Slot));
280 PyMem_Del(slots);
281 slots = NULL;
282
283 /* check that everything works */
284
285 PyTypeObject *class_tp = (PyTypeObject *)class;
286 PyHeapTypeObject *class_ht = (PyHeapTypeObject *)class;
287 assert(strcmp(class_tp->tp_name, "testcapi._Test") == 0);
288 assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_name), "_Test") == 0);
289 assert(strcmp(PyUnicode_AsUTF8(class_ht->ht_qualname), "_Test") == 0);
290 assert(strcmp(class_tp->tp_doc, "a test class") == 0);
291
292 // call and check __str__
293 instance = PyObject_CallNoArgs(class);
294 if (instance == NULL) {
295 goto finally;
296 }
297 obj = PyObject_Str(instance);
298 if (obj == NULL) {
299 goto finally;
300 }
301 assert(strcmp(PyUnicode_AsUTF8(obj), "<test>") == 0);
302 Py_CLEAR(obj);
303
304 result = Py_NewRef(Py_None);
305 finally:
306 PyMem_Del(spec);
307 PyMem_Del(name);
308 PyMem_Del(doc);
309 PyMem_Del(slots);
310 Py_XDECREF(class);
311 Py_XDECREF(instance);
312 Py_XDECREF(obj);
313 return result;
314 }
315
316 PyType_Slot repeated_doc_slots[] = {
317 {Py_tp_doc, "A class used for tests·"},
318 {Py_tp_doc, "A class used for tests"},
319 {0, 0},
320 };
321
322 PyType_Spec repeated_doc_slots_spec = {
323 .name = "RepeatedDocSlotClass",
324 .basicsize = sizeof(PyObject),
325 .slots = repeated_doc_slots,
326 };
327
328 typedef struct {
329 PyObject_HEAD
330 int data;
331 } HeapCTypeWithDataObject;
332
333
334 static struct PyMemberDef members_to_repeat[] = {
335 {"T_INT", T_INT, offsetof(HeapCTypeWithDataObject, data), 0, NULL},
336 {NULL}
337 };
338
339 PyType_Slot repeated_members_slots[] = {
340 {Py_tp_members, members_to_repeat},
341 {Py_tp_members, members_to_repeat},
342 {0, 0},
343 };
344
345 PyType_Spec repeated_members_slots_spec = {
346 .name = "RepeatedMembersSlotClass",
347 .basicsize = sizeof(HeapCTypeWithDataObject),
348 .slots = repeated_members_slots,
349 };
350
351 static PyObject *
352 create_type_from_repeated_slots(PyObject *self, PyObject *variant_obj)
353 {
354 PyObject *class = NULL;
355 int variant = PyLong_AsLong(variant_obj);
356 if (PyErr_Occurred()) {
357 return NULL;
358 }
359 switch (variant) {
360 case 0:
361 class = PyType_FromSpec(&repeated_doc_slots_spec);
362 break;
363 case 1:
364 class = PyType_FromSpec(&repeated_members_slots_spec);
365 break;
366 default:
367 PyErr_SetString(PyExc_ValueError, "bad test variant");
368 break;
369 }
370 return class;
371 }
372
373
374 static PyObject *
375 make_immutable_type_with_base(PyObject *self, PyObject *base)
376 {
377 assert(PyType_Check(base));
378 PyType_Spec ImmutableSubclass_spec = {
379 .name = "ImmutableSubclass",
380 .basicsize = (int)((PyTypeObject*)base)->tp_basicsize,
381 .slots = empty_type_slots,
382 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
383 };
384 return PyType_FromSpecWithBases(&ImmutableSubclass_spec, base);
385 }
386
387 static PyObject *
388 make_type_with_base(PyObject *self, PyObject *base)
389 {
390 assert(PyType_Check(base));
391 PyType_Spec ImmutableSubclass_spec = {
392 .name = "_testcapi.Subclass",
393 .basicsize = (int)((PyTypeObject*)base)->tp_basicsize,
394 .slots = empty_type_slots,
395 .flags = Py_TPFLAGS_DEFAULT,
396 };
397 return PyType_FromSpecWithBases(&ImmutableSubclass_spec, base);
398 }
399
400
401 static PyObject *
402 pyobject_getitemdata(PyObject *self, PyObject *o)
403 {
404 void *pointer = PyObject_GetItemData(o);
405 if (pointer == NULL) {
406 return NULL;
407 }
408 return PyLong_FromVoidPtr(pointer);
409 }
410
411
412 static PyMethodDef TestMethods[] = {
413 {"pytype_fromspec_meta", pytype_fromspec_meta, METH_O},
414 {"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS},
415 {"create_type_from_repeated_slots",
416 create_type_from_repeated_slots, METH_O},
417 {"test_from_spec_metatype_inheritance", test_from_spec_metatype_inheritance,
418 METH_NOARGS},
419 {"test_from_spec_invalid_metatype_inheritance",
420 test_from_spec_invalid_metatype_inheritance,
421 METH_NOARGS},
422 {"make_immutable_type_with_base", make_immutable_type_with_base, METH_O},
423 {"make_type_with_base", make_type_with_base, METH_O},
424 {"pyobject_getitemdata", pyobject_getitemdata, METH_O},
425 {NULL},
426 };
427
428
429 PyDoc_STRVAR(heapdocctype__doc__,
430 "HeapDocCType(arg1, arg2)\n"
431 "--\n"
432 "\n"
433 "somedoc");
434
435 typedef struct {
436 PyObject_HEAD
437 } HeapDocCTypeObject;
438
439 static PyType_Slot HeapDocCType_slots[] = {
440 {Py_tp_doc, (char*)heapdocctype__doc__},
441 {0},
442 };
443
444 static PyType_Spec HeapDocCType_spec = {
445 "_testcapi.HeapDocCType",
446 sizeof(HeapDocCTypeObject),
447 0,
448 Py_TPFLAGS_DEFAULT,
449 HeapDocCType_slots
450 };
451
452 typedef struct {
453 PyObject_HEAD
454 } NullTpDocTypeObject;
455
456 static PyType_Slot NullTpDocType_slots[] = {
457 {Py_tp_doc, NULL},
458 {0, 0},
459 };
460
461 static PyType_Spec NullTpDocType_spec = {
462 "_testcapi.NullTpDocType",
463 sizeof(NullTpDocTypeObject),
464 0,
465 Py_TPFLAGS_DEFAULT,
466 NullTpDocType_slots
467 };
468
469
470 PyDoc_STRVAR(heapgctype__doc__,
471 "A heap type with GC, and with overridden dealloc.\n\n"
472 "The 'value' attribute is set to 10 in __init__.");
473
474 typedef struct {
475 PyObject_HEAD
476 int value;
477 } HeapCTypeObject;
478
479 static struct PyMemberDef heapctype_members[] = {
480 {"value", T_INT, offsetof(HeapCTypeObject, value)},
481 {NULL} /* Sentinel */
482 };
483
484 static int
485 heapctype_init(PyObject *self, PyObject *args, PyObject *kwargs)
486 {
487 ((HeapCTypeObject *)self)->value = 10;
488 return 0;
489 }
490
491 static int
492 heapgcctype_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
493 {
494 Py_VISIT(Py_TYPE(self));
495 return 0;
496 }
497
498 static void
499 heapgcctype_dealloc(HeapCTypeObject *self)
500 {
501 PyTypeObject *tp = Py_TYPE(self);
502 PyObject_GC_UnTrack(self);
503 PyObject_GC_Del(self);
504 Py_DECREF(tp);
505 }
506
507 static PyType_Slot HeapGcCType_slots[] = {
508 {Py_tp_init, heapctype_init},
509 {Py_tp_members, heapctype_members},
510 {Py_tp_dealloc, heapgcctype_dealloc},
511 {Py_tp_traverse, heapgcctype_traverse},
512 {Py_tp_doc, (char*)heapgctype__doc__},
513 {0, 0},
514 };
515
516 static PyType_Spec HeapGcCType_spec = {
517 "_testcapi.HeapGcCType",
518 sizeof(HeapCTypeObject),
519 0,
520 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
521 HeapGcCType_slots
522 };
523
524 PyDoc_STRVAR(heapctype__doc__,
525 "A heap type without GC, but with overridden dealloc.\n\n"
526 "The 'value' attribute is set to 10 in __init__.");
527
528 static void
529 heapctype_dealloc(HeapCTypeObject *self)
530 {
531 PyTypeObject *tp = Py_TYPE(self);
532 PyObject_Free(self);
533 Py_DECREF(tp);
534 }
535
536 static PyType_Slot HeapCType_slots[] = {
537 {Py_tp_init, heapctype_init},
538 {Py_tp_members, heapctype_members},
539 {Py_tp_dealloc, heapctype_dealloc},
540 {Py_tp_doc, (char*)heapctype__doc__},
541 {0, 0},
542 };
543
544 static PyType_Spec HeapCType_spec = {
545 "_testcapi.HeapCType",
546 sizeof(HeapCTypeObject),
547 0,
548 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
549 HeapCType_slots
550 };
551
552 PyDoc_STRVAR(heapctypesubclass__doc__,
553 "Subclass of HeapCType, without GC.\n\n"
554 "__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
555
556 typedef struct {
557 HeapCTypeObject base;
558 int value2;
559 } HeapCTypeSubclassObject;
560
561 static int
562 heapctypesubclass_init(PyObject *self, PyObject *args, PyObject *kwargs)
563 {
564 /* Call __init__ of the superclass */
565 if (heapctype_init(self, args, kwargs) < 0) {
566 return -1;
567 }
568 /* Initialize additional element */
569 ((HeapCTypeSubclassObject *)self)->value2 = 20;
570 return 0;
571 }
572
573 static struct PyMemberDef heapctypesubclass_members[] = {
574 {"value2", T_INT, offsetof(HeapCTypeSubclassObject, value2)},
575 {NULL} /* Sentinel */
576 };
577
578 static PyType_Slot HeapCTypeSubclass_slots[] = {
579 {Py_tp_init, heapctypesubclass_init},
580 {Py_tp_members, heapctypesubclass_members},
581 {Py_tp_doc, (char*)heapctypesubclass__doc__},
582 {0, 0},
583 };
584
585 static PyType_Spec HeapCTypeSubclass_spec = {
586 "_testcapi.HeapCTypeSubclass",
587 sizeof(HeapCTypeSubclassObject),
588 0,
589 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
590 HeapCTypeSubclass_slots
591 };
592
593 PyDoc_STRVAR(heapctypewithbuffer__doc__,
594 "Heap type with buffer support.\n\n"
595 "The buffer is set to [b'1', b'2', b'3', b'4']");
596
597 typedef struct {
598 HeapCTypeObject base;
599 char buffer[4];
600 } HeapCTypeWithBufferObject;
601
602 static int
603 heapctypewithbuffer_getbuffer(HeapCTypeWithBufferObject *self, Py_buffer *view, int flags)
604 {
605 self->buffer[0] = '1';
606 self->buffer[1] = '2';
607 self->buffer[2] = '3';
608 self->buffer[3] = '4';
609 return PyBuffer_FillInfo(
610 view, (PyObject*)self, (void *)self->buffer, 4, 1, flags);
611 }
612
613 static void
614 heapctypewithbuffer_releasebuffer(HeapCTypeWithBufferObject *self, Py_buffer *view)
615 {
616 assert(view->obj == (void*) self);
617 }
618
619 static PyType_Slot HeapCTypeWithBuffer_slots[] = {
620 {Py_bf_getbuffer, heapctypewithbuffer_getbuffer},
621 {Py_bf_releasebuffer, heapctypewithbuffer_releasebuffer},
622 {Py_tp_doc, (char*)heapctypewithbuffer__doc__},
623 {0, 0},
624 };
625
626 static PyType_Spec HeapCTypeWithBuffer_spec = {
627 "_testcapi.HeapCTypeWithBuffer",
628 sizeof(HeapCTypeWithBufferObject),
629 0,
630 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
631 HeapCTypeWithBuffer_slots
632 };
633
634 PyDoc_STRVAR(heapctypesubclasswithfinalizer__doc__,
635 "Subclass of HeapCType with a finalizer that reassigns __class__.\n\n"
636 "__class__ is set to plain HeapCTypeSubclass during finalization.\n"
637 "__init__ sets the 'value' attribute to 10 and 'value2' to 20.");
638
639 static int
640 heapctypesubclasswithfinalizer_init(PyObject *self, PyObject *args, PyObject *kwargs)
641 {
642 PyTypeObject *base = (PyTypeObject *)PyType_GetSlot(Py_TYPE(self), Py_tp_base);
643 initproc base_init = PyType_GetSlot(base, Py_tp_init);
644 base_init(self, args, kwargs);
645 return 0;
646 }
647
648 static void
649 heapctypesubclasswithfinalizer_finalize(PyObject *self)
650 {
651 PyObject *oldtype = NULL, *newtype = NULL, *refcnt = NULL;
652
653 /* Save the current exception, if any. */
654 PyObject *exc = PyErr_GetRaisedException();
655
656 if (_testcapimodule == NULL) {
657 goto cleanup_finalize;
658 }
659 PyObject *m = PyState_FindModule(_testcapimodule);
660 if (m == NULL) {
661 goto cleanup_finalize;
662 }
663 oldtype = PyObject_GetAttrString(m, "HeapCTypeSubclassWithFinalizer");
664 if (oldtype == NULL) {
665 goto cleanup_finalize;
666 }
667 newtype = PyObject_GetAttrString(m, "HeapCTypeSubclass");
668 if (newtype == NULL) {
669 goto cleanup_finalize;
670 }
671
672 if (PyObject_SetAttrString(self, "__class__", newtype) < 0) {
673 goto cleanup_finalize;
674 }
675 refcnt = PyLong_FromSsize_t(Py_REFCNT(oldtype));
676 if (refcnt == NULL) {
677 goto cleanup_finalize;
678 }
679 if (PyObject_SetAttrString(oldtype, "refcnt_in_del", refcnt) < 0) {
680 goto cleanup_finalize;
681 }
682 Py_DECREF(refcnt);
683 refcnt = PyLong_FromSsize_t(Py_REFCNT(newtype));
684 if (refcnt == NULL) {
685 goto cleanup_finalize;
686 }
687 if (PyObject_SetAttrString(newtype, "refcnt_in_del", refcnt) < 0) {
688 goto cleanup_finalize;
689 }
690
691 cleanup_finalize:
692 Py_XDECREF(oldtype);
693 Py_XDECREF(newtype);
694 Py_XDECREF(refcnt);
695
696 /* Restore the saved exception. */
697 PyErr_SetRaisedException(exc);
698 }
699
700 static PyType_Slot HeapCTypeSubclassWithFinalizer_slots[] = {
701 {Py_tp_init, heapctypesubclasswithfinalizer_init},
702 {Py_tp_members, heapctypesubclass_members},
703 {Py_tp_finalize, heapctypesubclasswithfinalizer_finalize},
704 {Py_tp_doc, (char*)heapctypesubclasswithfinalizer__doc__},
705 {0, 0},
706 };
707
708 static PyType_Spec HeapCTypeSubclassWithFinalizer_spec = {
709 "_testcapi.HeapCTypeSubclassWithFinalizer",
710 sizeof(HeapCTypeSubclassObject),
711 0,
712 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE,
713 HeapCTypeSubclassWithFinalizer_slots
714 };
715
716 static PyType_Slot HeapCTypeMetaclass_slots[] = {
717 {0},
718 };
719
720 static PyType_Spec HeapCTypeMetaclass_spec = {
721 "_testcapi.HeapCTypeMetaclass",
722 sizeof(PyHeapTypeObject),
723 sizeof(PyMemberDef),
724 Py_TPFLAGS_DEFAULT,
725 HeapCTypeMetaclass_slots
726 };
727
728 static PyObject *
729 heap_ctype_metaclass_custom_tp_new(PyTypeObject *tp, PyObject *args, PyObject *kwargs)
730 {
731 return PyType_Type.tp_new(tp, args, kwargs);
732 }
733
734 static PyType_Slot HeapCTypeMetaclassCustomNew_slots[] = {
735 { Py_tp_new, heap_ctype_metaclass_custom_tp_new },
736 {0},
737 };
738
739 static PyType_Spec HeapCTypeMetaclassCustomNew_spec = {
740 "_testcapi.HeapCTypeMetaclassCustomNew",
741 sizeof(PyHeapTypeObject),
742 sizeof(PyMemberDef),
743 Py_TPFLAGS_DEFAULT,
744 HeapCTypeMetaclassCustomNew_slots
745 };
746
747 static PyType_Spec HeapCTypeMetaclassNullNew_spec = {
748 .name = "_testcapi.HeapCTypeMetaclassNullNew",
749 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
750 .slots = empty_type_slots
751 };
752
753
754 typedef struct {
755 PyObject_HEAD
756 PyObject *dict;
757 } HeapCTypeWithDictObject;
758
759 static void
760 heapctypewithdict_dealloc(HeapCTypeWithDictObject* self)
761 {
762
763 PyTypeObject *tp = Py_TYPE(self);
764 Py_XDECREF(self->dict);
765 PyObject_Free(self);
766 Py_DECREF(tp);
767 }
768
769 static PyGetSetDef heapctypewithdict_getsetlist[] = {
770 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
771 {NULL} /* Sentinel */
772 };
773
774 static struct PyMemberDef heapctypewithdict_members[] = {
775 {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
776 {"__dictoffset__", T_PYSSIZET, offsetof(HeapCTypeWithDictObject, dict), READONLY},
777 {NULL} /* Sentinel */
778 };
779
780 static PyType_Slot HeapCTypeWithDict_slots[] = {
781 {Py_tp_members, heapctypewithdict_members},
782 {Py_tp_getset, heapctypewithdict_getsetlist},
783 {Py_tp_dealloc, heapctypewithdict_dealloc},
784 {0, 0},
785 };
786
787 static PyType_Spec HeapCTypeWithDict_spec = {
788 "_testcapi.HeapCTypeWithDict",
789 sizeof(HeapCTypeWithDictObject),
790 0,
791 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
792 HeapCTypeWithDict_slots
793 };
794
795 static PyType_Spec HeapCTypeWithDict2_spec = {
796 "_testcapi.HeapCTypeWithDict2",
797 sizeof(HeapCTypeWithDictObject),
798 0,
799 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
800 HeapCTypeWithDict_slots
801 };
802
803 static int
804 heapmanaged_traverse(HeapCTypeObject *self, visitproc visit, void *arg)
805 {
806 Py_VISIT(Py_TYPE(self));
807 return _PyObject_VisitManagedDict((PyObject *)self, visit, arg);
808 }
809
810 static int
811 heapmanaged_clear(HeapCTypeObject *self)
812 {
813 _PyObject_ClearManagedDict((PyObject *)self);
814 return 0;
815 }
816
817 static void
818 heapmanaged_dealloc(HeapCTypeObject *self)
819 {
820 PyTypeObject *tp = Py_TYPE(self);
821 _PyObject_ClearManagedDict((PyObject *)self);
822 PyObject_GC_UnTrack(self);
823 PyObject_GC_Del(self);
824 Py_DECREF(tp);
825 }
826
827 static PyType_Slot HeapCTypeWithManagedDict_slots[] = {
828 {Py_tp_traverse, heapmanaged_traverse},
829 {Py_tp_getset, heapctypewithdict_getsetlist},
830 {Py_tp_clear, heapmanaged_clear},
831 {Py_tp_dealloc, heapmanaged_dealloc},
832 {0, 0},
833 };
834
835 static PyType_Spec HeapCTypeWithManagedDict_spec = {
836 "_testcapi.HeapCTypeWithManagedDict",
837 sizeof(PyObject),
838 0,
839 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_DICT,
840 HeapCTypeWithManagedDict_slots
841 };
842
843 static void
844 heapctypewithmanagedweakref_dealloc(PyObject* self)
845 {
846
847 PyTypeObject *tp = Py_TYPE(self);
848 PyObject_ClearWeakRefs(self);
849 PyObject_GC_UnTrack(self);
850 PyObject_GC_Del(self);
851 Py_DECREF(tp);
852 }
853
854 static PyType_Slot HeapCTypeWithManagedWeakref_slots[] = {
855 {Py_tp_traverse, heapgcctype_traverse},
856 {Py_tp_getset, heapctypewithdict_getsetlist},
857 {Py_tp_dealloc, heapctypewithmanagedweakref_dealloc},
858 {0, 0},
859 };
860
861 static PyType_Spec HeapCTypeWithManagedWeakref_spec = {
862 "_testcapi.HeapCTypeWithManagedWeakref",
863 sizeof(PyObject),
864 0,
865 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_WEAKREF,
866 HeapCTypeWithManagedWeakref_slots
867 };
868
869 static struct PyMemberDef heapctypewithnegativedict_members[] = {
870 {"dictobj", T_OBJECT, offsetof(HeapCTypeWithDictObject, dict)},
871 {"__dictoffset__", T_PYSSIZET, -(Py_ssize_t)sizeof(void*), READONLY},
872 {NULL} /* Sentinel */
873 };
874
875 static PyType_Slot HeapCTypeWithNegativeDict_slots[] = {
876 {Py_tp_members, heapctypewithnegativedict_members},
877 {Py_tp_getset, heapctypewithdict_getsetlist},
878 {Py_tp_dealloc, heapctypewithdict_dealloc},
879 {0, 0},
880 };
881
882 static PyType_Spec HeapCTypeWithNegativeDict_spec = {
883 "_testcapi.HeapCTypeWithNegativeDict",
884 sizeof(HeapCTypeWithDictObject),
885 0,
886 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
887 HeapCTypeWithNegativeDict_slots
888 };
889
890 typedef struct {
891 PyObject_HEAD
892 PyObject *weakreflist;
893 } HeapCTypeWithWeakrefObject;
894
895 static struct PyMemberDef heapctypewithweakref_members[] = {
896 {"weakreflist", T_OBJECT, offsetof(HeapCTypeWithWeakrefObject, weakreflist)},
897 {"__weaklistoffset__", T_PYSSIZET,
898 offsetof(HeapCTypeWithWeakrefObject, weakreflist), READONLY},
899 {NULL} /* Sentinel */
900 };
901
902 static void
903 heapctypewithweakref_dealloc(HeapCTypeWithWeakrefObject* self)
904 {
905
906 PyTypeObject *tp = Py_TYPE(self);
907 if (self->weakreflist != NULL)
908 PyObject_ClearWeakRefs((PyObject *) self);
909 Py_XDECREF(self->weakreflist);
910 PyObject_Free(self);
911 Py_DECREF(tp);
912 }
913
914 static PyType_Slot HeapCTypeWithWeakref_slots[] = {
915 {Py_tp_members, heapctypewithweakref_members},
916 {Py_tp_dealloc, heapctypewithweakref_dealloc},
917 {0, 0},
918 };
919
920 static PyType_Spec HeapCTypeWithWeakref_spec = {
921 "_testcapi.HeapCTypeWithWeakref",
922 sizeof(HeapCTypeWithWeakrefObject),
923 0,
924 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
925 HeapCTypeWithWeakref_slots
926 };
927
928 static PyType_Spec HeapCTypeWithWeakref2_spec = {
929 "_testcapi.HeapCTypeWithWeakref2",
930 sizeof(HeapCTypeWithWeakrefObject),
931 0,
932 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
933 HeapCTypeWithWeakref_slots
934 };
935
936 PyDoc_STRVAR(heapctypesetattr__doc__,
937 "A heap type without GC, but with overridden __setattr__.\n\n"
938 "The 'value' attribute is set to 10 in __init__ and updated via attribute setting.");
939
940 typedef struct {
941 PyObject_HEAD
942 long value;
943 } HeapCTypeSetattrObject;
944
945 static struct PyMemberDef heapctypesetattr_members[] = {
946 {"pvalue", T_LONG, offsetof(HeapCTypeSetattrObject, value)},
947 {NULL} /* Sentinel */
948 };
949
950 static int
951 heapctypesetattr_init(PyObject *self, PyObject *args, PyObject *kwargs)
952 {
953 ((HeapCTypeSetattrObject *)self)->value = 10;
954 return 0;
955 }
956
957 static void
958 heapctypesetattr_dealloc(HeapCTypeSetattrObject *self)
959 {
960 PyTypeObject *tp = Py_TYPE(self);
961 PyObject_Free(self);
962 Py_DECREF(tp);
963 }
964
965 static int
966 heapctypesetattr_setattro(HeapCTypeSetattrObject *self, PyObject *attr, PyObject *value)
967 {
968 PyObject *svalue = PyUnicode_FromString("value");
969 if (svalue == NULL)
970 return -1;
971 int eq = PyObject_RichCompareBool(svalue, attr, Py_EQ);
972 Py_DECREF(svalue);
973 if (eq < 0)
974 return -1;
975 if (!eq) {
976 return PyObject_GenericSetAttr((PyObject*) self, attr, value);
977 }
978 if (value == NULL) {
979 self->value = 0;
980 return 0;
981 }
982 PyObject *ivalue = PyNumber_Long(value);
983 if (ivalue == NULL)
984 return -1;
985 long v = PyLong_AsLong(ivalue);
986 Py_DECREF(ivalue);
987 if (v == -1 && PyErr_Occurred())
988 return -1;
989 self->value = v;
990 return 0;
991 }
992
993 static PyType_Slot HeapCTypeSetattr_slots[] = {
994 {Py_tp_init, heapctypesetattr_init},
995 {Py_tp_members, heapctypesetattr_members},
996 {Py_tp_setattro, heapctypesetattr_setattro},
997 {Py_tp_dealloc, heapctypesetattr_dealloc},
998 {Py_tp_doc, (char*)heapctypesetattr__doc__},
999 {0, 0},
1000 };
1001
1002 static PyType_Spec HeapCTypeSetattr_spec = {
1003 "_testcapi.HeapCTypeSetattr",
1004 sizeof(HeapCTypeSetattrObject),
1005 0,
1006 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1007 HeapCTypeSetattr_slots
1008 };
1009
1010 PyDoc_STRVAR(HeapCCollection_doc,
1011 "Tuple-like heap type that uses PyObject_GetItemData for items.");
1012
1013 static PyObject*
1014 HeapCCollection_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
1015 {
1016 PyObject *self = NULL;
1017 PyObject *result = NULL;
1018
1019 Py_ssize_t size = PyTuple_GET_SIZE(args);
1020 self = subtype->tp_alloc(subtype, size);
1021 if (!self) {
1022 goto finally;
1023 }
1024 PyObject **data = PyObject_GetItemData(self);
1025 if (!data) {
1026 goto finally;
1027 }
1028
1029 for (Py_ssize_t i = 0; i < size; i++) {
1030 data[i] = Py_NewRef(PyTuple_GET_ITEM(args, i));
1031 }
1032
1033 result = self;
1034 self = NULL;
1035 finally:
1036 Py_XDECREF(self);
1037 return result;
1038 }
1039
1040 static Py_ssize_t
1041 HeapCCollection_length(PyVarObject *self)
1042 {
1043 return Py_SIZE(self);
1044 }
1045
1046 static PyObject*
1047 HeapCCollection_item(PyObject *self, Py_ssize_t i)
1048 {
1049 if (i < 0 || i >= Py_SIZE(self)) {
1050 return PyErr_Format(PyExc_IndexError, "index %zd out of range", i);
1051 }
1052 PyObject **data = PyObject_GetItemData(self);
1053 if (!data) {
1054 return NULL;
1055 }
1056 return Py_NewRef(data[i]);
1057 }
1058
1059 static int
1060 HeapCCollection_traverse(PyObject *self, visitproc visit, void *arg)
1061 {
1062 PyObject **data = PyObject_GetItemData(self);
1063 if (!data) {
1064 return -1;
1065 }
1066 for (Py_ssize_t i = 0; i < Py_SIZE(self); i++) {
1067 Py_VISIT(data[i]);
1068 }
1069 return 0;
1070 }
1071
1072 static int
1073 HeapCCollection_clear(PyObject *self)
1074 {
1075 PyObject **data = PyObject_GetItemData(self);
1076 if (!data) {
1077 return -1;
1078 }
1079 Py_ssize_t size = Py_SIZE(self);
1080 Py_SET_SIZE(self, 0);
1081 for (Py_ssize_t i = 0; i < size; i++) {
1082 Py_CLEAR(data[i]);
1083 }
1084 return 0;
1085 }
1086
1087 static void
1088 HeapCCollection_dealloc(PyObject *self)
1089 {
1090 PyTypeObject *tp = Py_TYPE(self);
1091 HeapCCollection_clear(self);
1092 PyObject_GC_UnTrack(self);
1093 tp->tp_free(self);
1094 Py_DECREF(tp);
1095 }
1096
1097 static PyType_Slot HeapCCollection_slots[] = {
1098 {Py_tp_new, HeapCCollection_new},
1099 {Py_sq_length, HeapCCollection_length},
1100 {Py_sq_item, HeapCCollection_item},
1101 {Py_tp_traverse, HeapCCollection_traverse},
1102 {Py_tp_clear, HeapCCollection_clear},
1103 {Py_tp_dealloc, HeapCCollection_dealloc},
1104 {Py_tp_doc, (void *)HeapCCollection_doc},
1105 {0, 0},
1106 };
1107
1108 static PyType_Spec HeapCCollection_spec = {
1109 .name = "_testcapi.HeapCCollection",
1110 .basicsize = sizeof(PyVarObject),
1111 .itemsize = sizeof(PyObject*),
1112 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
1113 Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_ITEMS_AT_END),
1114 .slots = HeapCCollection_slots,
1115 };
1116
1117 int
1118 _PyTestCapi_Init_Heaptype(PyObject *m) {
1119 _testcapimodule = PyModule_GetDef(m);
1120
1121 if (PyModule_AddFunctions(m, TestMethods) < 0) {
1122 return -1;
1123 }
1124
1125 PyObject *HeapDocCType = PyType_FromSpec(&HeapDocCType_spec);
1126 if (HeapDocCType == NULL) {
1127 return -1;
1128 }
1129 PyModule_AddObject(m, "HeapDocCType", HeapDocCType);
1130
1131 /* bpo-41832: Add a new type to test PyType_FromSpec()
1132 now can accept a NULL tp_doc slot. */
1133 PyObject *NullTpDocType = PyType_FromSpec(&NullTpDocType_spec);
1134 if (NullTpDocType == NULL) {
1135 return -1;
1136 }
1137 PyModule_AddObject(m, "NullTpDocType", NullTpDocType);
1138
1139 PyObject *HeapGcCType = PyType_FromSpec(&HeapGcCType_spec);
1140 if (HeapGcCType == NULL) {
1141 return -1;
1142 }
1143 PyModule_AddObject(m, "HeapGcCType", HeapGcCType);
1144
1145 PyObject *HeapCType = PyType_FromSpec(&HeapCType_spec);
1146 if (HeapCType == NULL) {
1147 return -1;
1148 }
1149 PyObject *subclass_bases = PyTuple_Pack(1, HeapCType);
1150 if (subclass_bases == NULL) {
1151 return -1;
1152 }
1153 PyObject *HeapCTypeSubclass = PyType_FromSpecWithBases(&HeapCTypeSubclass_spec, subclass_bases);
1154 if (HeapCTypeSubclass == NULL) {
1155 return -1;
1156 }
1157 Py_DECREF(subclass_bases);
1158 PyModule_AddObject(m, "HeapCTypeSubclass", HeapCTypeSubclass);
1159
1160 PyObject *HeapCTypeWithDict = PyType_FromSpec(&HeapCTypeWithDict_spec);
1161 if (HeapCTypeWithDict == NULL) {
1162 return -1;
1163 }
1164 PyModule_AddObject(m, "HeapCTypeWithDict", HeapCTypeWithDict);
1165
1166 PyObject *HeapCTypeWithDict2 = PyType_FromSpec(&HeapCTypeWithDict2_spec);
1167 if (HeapCTypeWithDict2 == NULL) {
1168 return -1;
1169 }
1170 PyModule_AddObject(m, "HeapCTypeWithDict2", HeapCTypeWithDict2);
1171
1172 PyObject *HeapCTypeWithNegativeDict = PyType_FromSpec(&HeapCTypeWithNegativeDict_spec);
1173 if (HeapCTypeWithNegativeDict == NULL) {
1174 return -1;
1175 }
1176 PyModule_AddObject(m, "HeapCTypeWithNegativeDict", HeapCTypeWithNegativeDict);
1177
1178 PyObject *HeapCTypeWithManagedDict = PyType_FromSpec(&HeapCTypeWithManagedDict_spec);
1179 if (HeapCTypeWithManagedDict == NULL) {
1180 return -1;
1181 }
1182 PyModule_AddObject(m, "HeapCTypeWithManagedDict", HeapCTypeWithManagedDict);
1183
1184 PyObject *HeapCTypeWithManagedWeakref = PyType_FromSpec(&HeapCTypeWithManagedWeakref_spec);
1185 if (HeapCTypeWithManagedWeakref == NULL) {
1186 return -1;
1187 }
1188 PyModule_AddObject(m, "HeapCTypeWithManagedWeakref", HeapCTypeWithManagedWeakref);
1189
1190 PyObject *HeapCTypeWithWeakref = PyType_FromSpec(&HeapCTypeWithWeakref_spec);
1191 if (HeapCTypeWithWeakref == NULL) {
1192 return -1;
1193 }
1194 PyModule_AddObject(m, "HeapCTypeWithWeakref", HeapCTypeWithWeakref);
1195
1196 PyObject *HeapCTypeWithWeakref2 = PyType_FromSpec(&HeapCTypeWithWeakref2_spec);
1197 if (HeapCTypeWithWeakref2 == NULL) {
1198 return -1;
1199 }
1200 PyModule_AddObject(m, "HeapCTypeWithWeakref2", HeapCTypeWithWeakref2);
1201
1202 PyObject *HeapCTypeWithBuffer = PyType_FromSpec(&HeapCTypeWithBuffer_spec);
1203 if (HeapCTypeWithBuffer == NULL) {
1204 return -1;
1205 }
1206 PyModule_AddObject(m, "HeapCTypeWithBuffer", HeapCTypeWithBuffer);
1207
1208 PyObject *HeapCTypeSetattr = PyType_FromSpec(&HeapCTypeSetattr_spec);
1209 if (HeapCTypeSetattr == NULL) {
1210 return -1;
1211 }
1212 PyModule_AddObject(m, "HeapCTypeSetattr", HeapCTypeSetattr);
1213
1214 PyObject *subclass_with_finalizer_bases = PyTuple_Pack(1, HeapCTypeSubclass);
1215 if (subclass_with_finalizer_bases == NULL) {
1216 return -1;
1217 }
1218 PyObject *HeapCTypeSubclassWithFinalizer = PyType_FromSpecWithBases(
1219 &HeapCTypeSubclassWithFinalizer_spec, subclass_with_finalizer_bases);
1220 if (HeapCTypeSubclassWithFinalizer == NULL) {
1221 return -1;
1222 }
1223 Py_DECREF(subclass_with_finalizer_bases);
1224 PyModule_AddObject(m, "HeapCTypeSubclassWithFinalizer", HeapCTypeSubclassWithFinalizer);
1225
1226 PyObject *HeapCTypeMetaclass = PyType_FromMetaclass(
1227 &PyType_Type, m, &HeapCTypeMetaclass_spec, (PyObject *) &PyType_Type);
1228 if (HeapCTypeMetaclass == NULL) {
1229 return -1;
1230 }
1231 PyModule_AddObject(m, "HeapCTypeMetaclass", HeapCTypeMetaclass);
1232
1233 PyObject *HeapCTypeMetaclassCustomNew = PyType_FromMetaclass(
1234 &PyType_Type, m, &HeapCTypeMetaclassCustomNew_spec, (PyObject *) &PyType_Type);
1235 if (HeapCTypeMetaclassCustomNew == NULL) {
1236 return -1;
1237 }
1238 PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew);
1239
1240 PyObject *HeapCTypeMetaclassNullNew = PyType_FromMetaclass(
1241 &PyType_Type, m, &HeapCTypeMetaclassNullNew_spec, (PyObject *) &PyType_Type);
1242 if (HeapCTypeMetaclassNullNew == NULL) {
1243 return -1;
1244 }
1245 PyModule_AddObject(m, "HeapCTypeMetaclassNullNew", HeapCTypeMetaclassNullNew);
1246
1247 PyObject *HeapCCollection = PyType_FromMetaclass(
1248 NULL, m, &HeapCCollection_spec, NULL);
1249 if (HeapCCollection == NULL) {
1250 return -1;
1251 }
1252 int rc = PyModule_AddType(m, (PyTypeObject *)HeapCCollection);
1253 Py_DECREF(HeapCCollection);
1254 if (rc < 0) {
1255 return -1;
1256 }
1257
1258 return 0;
1259 }