Skip to content

Commit ad61063

Browse files
committed
Add regression test
1 parent f25cc82 commit ad61063

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

Lib/test/test_capi/test_type.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,10 @@ class FreezeThis(metaclass=Meta):
6767
Base.value = 3
6868
type_freeze(FreezeThis)
6969
self.assertEqual(FreezeThis.value, 2)
70+
71+
def test_manual_heap_type(self):
72+
# gh-128923: test that a manually allocated and initailized heap type
73+
# works correctly
74+
ManualHeapType = _testcapi.ManualHeapType
75+
for i in range(100):
76+
self.assertIsInstance(ManualHeapType(), ManualHeapType)

Modules/_testcapimodule.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4149,6 +4149,61 @@ static PyTypeObject ContainerNoGC_type = {
41494149
.tp_new = ContainerNoGC_new,
41504150
};
41514151

4152+
/* Manually allocated heap type */
4153+
4154+
typedef struct {
4155+
PyObject_HEAD
4156+
PyObject *dict;
4157+
} ManualHeapType;
4158+
4159+
static int
4160+
ManualHeapType_traverse(PyObject *self, visitproc visit, void *arg)
4161+
{
4162+
ManualHeapType *mht = (ManualHeapType *)self;
4163+
Py_VISIT(mht->dict);
4164+
return 0;
4165+
}
4166+
4167+
static void
4168+
ManualHeapType_dealloc(PyObject *self)
4169+
{
4170+
ManualHeapType *mht = (ManualHeapType *)self;
4171+
PyObject_GC_UnTrack(self);
4172+
Py_XDECREF(mht->dict);
4173+
PyTypeObject *type = Py_TYPE(self);
4174+
Py_TYPE(self)->tp_free(self);
4175+
Py_DECREF(type);
4176+
}
4177+
4178+
static PyObject *
4179+
create_manual_heap_type(void)
4180+
{
4181+
// gh-128923: Ensure that a heap type allocated through PyType_Type.tp_alloc
4182+
// with minimal initialization works correctly.
4183+
PyHeapTypeObject *heap_type = (PyHeapTypeObject *)PyType_Type.tp_alloc(&PyType_Type, 0);
4184+
if (heap_type == NULL) {
4185+
return NULL;
4186+
}
4187+
PyTypeObject* type = &heap_type->ht_type;
4188+
type->tp_basicsize = sizeof(ManualHeapType);
4189+
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_HAVE_GC;
4190+
type->tp_new = PyType_GenericNew;
4191+
type->tp_name = "ManualHeapType";
4192+
type->tp_dictoffset = offsetof(ManualHeapType, dict);
4193+
type->tp_traverse = ManualHeapType_traverse;
4194+
type->tp_dealloc = ManualHeapType_dealloc;
4195+
heap_type->ht_name = PyUnicode_FromString(type->tp_name);
4196+
if (!heap_type->ht_name) {
4197+
Py_DECREF(type);
4198+
return NULL;
4199+
}
4200+
heap_type->ht_qualname = Py_NewRef(heap_type->ht_name);
4201+
if (PyType_Ready(type) < 0) {
4202+
Py_DECREF(type);
4203+
return NULL;
4204+
}
4205+
return (PyObject *)type;
4206+
}
41524207

41534208
static struct PyModuleDef _testcapimodule = {
41544209
PyModuleDef_HEAD_INIT,
@@ -4283,6 +4338,15 @@ PyInit__testcapi(void)
42834338
(PyObject *) &ContainerNoGC_type) < 0)
42844339
return NULL;
42854340

4341+
PyObject *manual_heap_type = create_manual_heap_type();
4342+
if (manual_heap_type == NULL) {
4343+
return NULL;
4344+
}
4345+
if (PyModule_AddObject(m, "ManualHeapType", manual_heap_type) < 0) {
4346+
return NULL;
4347+
}
4348+
4349+
42864350
/* Include tests from the _testcapi/ directory */
42874351
if (_PyTestCapi_Init_Vectorcall(m) < 0) {
42884352
return NULL;

0 commit comments

Comments
 (0)