@@ -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
41534208static 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