@@ -3105,16 +3105,6 @@ PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
31053105 return 0 ;
31063106}
31073107
3108- /*
3109- * CData objects are mutable, so they cannot be hashable!
3110- */
3111- static Py_hash_t
3112- PyCData_nohash (PyObject * self )
3113- {
3114- PyErr_SetString (PyExc_TypeError , "unhashable type" );
3115- return -1 ;
3116- }
3117-
31183108/*[clinic input]
31193109@critical_section
31203110_ctypes.PyCData.__reduce__
@@ -3211,25 +3201,40 @@ static PyMethodDef PyCData_methods[] = {
32113201 { NULL , NULL },
32123202};
32133203
3214- static PyType_Slot pycdata_slots [] = {
3215- {Py_tp_dealloc , PyCData_dealloc },
3216- {Py_tp_hash , PyCData_nohash },
3217- {Py_tp_doc , PyDoc_STR ("XXX to be provided" )},
3218- {Py_tp_traverse , PyCData_traverse },
3219- {Py_tp_clear , PyCData_clear },
3220- {Py_tp_methods , PyCData_methods },
3221- {Py_tp_members , PyCData_members },
3222- {Py_bf_getbuffer , PyCData_NewGetBuffer },
3223- {0 , NULL },
3224- };
3225-
3226- static PyType_Spec pycdata_spec = {
3227- .name = "_ctypes._CData" ,
3228- .basicsize = sizeof (CDataObject ),
3229- .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
3230- Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION ),
3231- .slots = pycdata_slots ,
3232- };
3204+ /*
3205+ * CData objects are mutable, so they cannot be hashable. Setting tp_hash to
3206+ * PyObject_HashNotImplemented() makes type_ready() set __hash__ to None.
3207+ *
3208+ * Unfortunately, on Windows, PyObject_HashNotImplemented is imported from
3209+ * the Python DLL, and MSVC resolves the address of an imported function in
3210+ * a static initializer to a local thunk that can't be recognized. So, we
3211+ * initialize the slots at runtime to load the real address from the import table.
3212+ */
3213+ static PyObject *
3214+ PyCData_create_type (PyObject * mod )
3215+ {
3216+ PyType_Slot slots [] = {
3217+ {Py_tp_dealloc , PyCData_dealloc },
3218+ {Py_tp_hash , PyObject_HashNotImplemented },
3219+ {Py_tp_doc , PyDoc_STR ("The common base class of all ctypes "
3220+ "data types." )},
3221+ {Py_tp_traverse , PyCData_traverse },
3222+ {Py_tp_clear , PyCData_clear },
3223+ {Py_tp_methods , PyCData_methods },
3224+ {Py_tp_members , PyCData_members },
3225+ {Py_bf_getbuffer , PyCData_NewGetBuffer },
3226+ {0 , NULL },
3227+ };
3228+ PyType_Spec spec = {
3229+ .name = "_ctypes._CData" ,
3230+ .basicsize = sizeof (CDataObject ),
3231+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
3232+ Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE |
3233+ Py_TPFLAGS_DISALLOW_INSTANTIATION ),
3234+ .slots = slots ,
3235+ };
3236+ return PyType_FromMetaclass (NULL , mod , & spec , NULL );
3237+ }
32333238
32343239static int
32353240PyCData_MallocBuffer (CDataObject * obj , StgInfo * info )
@@ -6249,7 +6254,10 @@ _ctypes_add_types(PyObject *mod)
62496254 */
62506255 CREATE_TYPE (st -> PyCArg_Type , & carg_spec , NULL , NULL );
62516256 CREATE_TYPE (st -> PyCThunk_Type , & cthunk_spec , NULL , NULL );
6252- CREATE_TYPE (st -> PyCData_Type , & pycdata_spec , NULL , NULL );
6257+ st -> PyCData_Type = (PyTypeObject * )PyCData_create_type (mod );
6258+ if (st -> PyCData_Type == NULL ) {
6259+ return -1 ;
6260+ }
62536261
62546262 // Common Metaclass
62556263 CREATE_TYPE (st -> PyCType_Type , & pyctype_type_spec ,
0 commit comments