Skip to content

Commit 08b6a77

Browse files
committed
Stupid MSVC ruining my day.
1 parent dcee516 commit 08b6a77

1 file changed

Lines changed: 37 additions & 20 deletions

File tree

‎Modules/_ctypes/_ctypes.c‎

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3201,25 +3201,39 @@ static PyMethodDef PyCData_methods[] = {
32013201
{ NULL, NULL },
32023202
};
32033203

3204-
static PyType_Slot pycdata_slots[] = {
3205-
{Py_tp_dealloc, PyCData_dealloc},
3206-
{Py_tp_hash, PyObject_HashNotImplemented},
3207-
{Py_tp_doc, PyDoc_STR("XXX to be provided")},
3208-
{Py_tp_traverse, PyCData_traverse},
3209-
{Py_tp_clear, PyCData_clear},
3210-
{Py_tp_methods, PyCData_methods},
3211-
{Py_tp_members, PyCData_members},
3212-
{Py_bf_getbuffer, PyCData_NewGetBuffer},
3213-
{0, NULL},
3214-
};
3215-
3216-
static PyType_Spec pycdata_spec = {
3217-
.name = "_ctypes._CData",
3218-
.basicsize = sizeof(CDataObject),
3219-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
3220-
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
3221-
.slots = pycdata_slots,
3222-
};
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("XXX to be provided")},
3220+
{Py_tp_traverse, PyCData_traverse},
3221+
{Py_tp_clear, PyCData_clear},
3222+
{Py_tp_methods, PyCData_methods},
3223+
{Py_tp_members, PyCData_members},
3224+
{Py_bf_getbuffer, PyCData_NewGetBuffer},
3225+
{0, NULL},
3226+
};
3227+
PyType_Spec spec = {
3228+
.name = "_ctypes._CData",
3229+
.basicsize = sizeof(CDataObject),
3230+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
3231+
Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE |
3232+
Py_TPFLAGS_DISALLOW_INSTANTIATION),
3233+
.slots = slots,
3234+
};
3235+
return PyType_FromMetaclass(NULL, mod, &spec, NULL);
3236+
}
32233237

32243238
static int
32253239
PyCData_MallocBuffer(CDataObject *obj, StgInfo *info)
@@ -6239,7 +6253,10 @@ _ctypes_add_types(PyObject *mod)
62396253
*/
62406254
CREATE_TYPE(st->PyCArg_Type, &carg_spec, NULL, NULL);
62416255
CREATE_TYPE(st->PyCThunk_Type, &cthunk_spec, NULL, NULL);
6242-
CREATE_TYPE(st->PyCData_Type, &pycdata_spec, NULL, NULL);
6256+
st->PyCData_Type = (PyTypeObject *)PyCData_create_type(mod);
6257+
if (st->PyCData_Type == NULL) {
6258+
return -1;
6259+
}
62436260

62446261
// Common Metaclass
62456262
CREATE_TYPE(st->PyCType_Type, &pyctype_type_spec,

0 commit comments

Comments
 (0)