Skip to content

gh-117142: ctypes: Unify meta tp slot functions #117143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 1, 2024
109 changes: 36 additions & 73 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,19 +441,35 @@ static PyType_Spec structparam_spec = {
static int
CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
{
ctypes_state *st = GLOBAL_STATE();
if (st && st->PyCType_Type) {
StgInfo *info;
if (PyStgInfo_FromType(st, self, &info) < 0) {
PyErr_WriteUnraisable(self);
}
if (info) {
Py_VISIT(info->proto);
Py_VISIT(info->argtypes);
Py_VISIT(info->converters);
Py_VISIT(info->restype);
Py_VISIT(info->checker);
Py_VISIT(info->module);
}
}
Py_VISIT(Py_TYPE(self));
return 0;
return PyType_Type.tp_traverse(self, visit, arg);
}

static void
_ctype_clear_stginfo(StgInfo *info)
void
ctype_clear_stginfo(StgInfo *info)
{
assert(info);
Py_CLEAR(info->proto);
Py_CLEAR(info->argtypes);
Py_CLEAR(info->converters);
Py_CLEAR(info->restype);
Py_CLEAR(info->checker);
Py_CLEAR(info->module);
}

static int
Expand All @@ -463,13 +479,13 @@ CType_Type_clear(PyObject *self)
if (st && st->PyCType_Type) {
StgInfo *info;
if (PyStgInfo_FromType(st, self, &info) < 0) {
return -1;
PyErr_WriteUnraisable(self);
}
if (info) {
_ctype_clear_stginfo(info);
ctype_clear_stginfo(info);
}
}
return 0;
return PyType_Type.tp_clear(self);
}

static void
Expand All @@ -489,7 +505,7 @@ CType_Type_dealloc(PyObject *self)
info->format = NULL;
PyMem_Free(info->shape);
info->shape = NULL;
_ctype_clear_stginfo(info);
ctype_clear_stginfo(info);
}
}

Expand Down Expand Up @@ -522,6 +538,10 @@ CType_Type_sizeof(PyObject *self)
return PyLong_FromSsize_t(size);
}

static PyObject *
CType_Type_repeat(PyObject *self, Py_ssize_t length);


static PyMethodDef ctype_methods[] = {
{"__sizeof__", _PyCFunction_CAST(CType_Type_sizeof),
METH_NOARGS, PyDoc_STR("Return memory consumption of the type object.")},
Expand All @@ -533,6 +553,8 @@ static PyType_Slot ctype_type_slots[] = {
{Py_tp_clear, CType_Type_clear},
{Py_tp_dealloc, CType_Type_dealloc},
{Py_tp_methods, ctype_methods},
// Sequence protocol.
{Py_sq_repeat, CType_Type_repeat},
{0, NULL},
};

Expand Down Expand Up @@ -978,7 +1000,7 @@ static PyMethodDef CDataType_methods[] = {
};

static PyObject *
CDataType_repeat(PyObject *self, Py_ssize_t length)
CType_Type_repeat(PyObject *self, Py_ssize_t length)
{
if (length < 0)
return PyErr_Format(PyExc_ValueError,
Expand All @@ -988,35 +1010,6 @@ CDataType_repeat(PyObject *self, Py_ssize_t length)
return PyCArrayType_from_ctype(st, self, length);
}

static int
CDataType_clear(PyTypeObject *self)
{
ctypes_state *st = GLOBAL_STATE();
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)self, &info) < 0) {
return -1;
}
if (info) {
Py_CLEAR(info->proto);
}
return PyType_Type.tp_clear((PyObject *)self);
}

static int
CDataType_traverse(PyTypeObject *self, visitproc visit, void *arg)
{
ctypes_state *st = GLOBAL_STATE();
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)self, &info) < 0) {
return -1;
}
if (info) {
Py_VISIT(info->proto);
}
Py_VISIT(Py_TYPE(self));
return PyType_Type.tp_traverse((PyObject *)self, visit, arg);
}

static int
PyCStructType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
Expand Down Expand Up @@ -1047,39 +1040,29 @@ UnionType_setattro(PyObject *self, PyObject *key, PyObject *value)
static PyType_Slot pycstruct_type_slots[] = {
{Py_tp_setattro, PyCStructType_setattro},
{Py_tp_doc, PyDoc_STR("metatype for the CData Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
{Py_tp_init, PyCStructType_init},

// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};

static PyType_Spec pycstruct_type_spec = {
.name = "_ctypes.PyCStructType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycstruct_type_slots,
};

static PyType_Slot union_type_slots[] = {
{Py_tp_setattro, UnionType_setattro},
{Py_tp_doc, PyDoc_STR("metatype for the Union Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
{Py_tp_init, UnionType_init},

// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};

static PyType_Spec union_type_spec = {
.name = "_ctypes.UnionType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = union_type_slots,
};
Expand Down Expand Up @@ -1305,19 +1288,14 @@ static PyMethodDef PyCPointerType_methods[] = {

static PyType_Slot pycpointer_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the Pointer Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, PyCPointerType_methods},
{Py_tp_init, PyCPointerType_init},

// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};

static PyType_Spec pycpointer_type_spec = {
.name = "_ctypes.PyCPointerType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycpointer_type_slots,
};
Expand Down Expand Up @@ -1640,19 +1618,14 @@ PyCArrayType_init(PyObject *self, PyObject *args, PyObject *kwds)

static PyType_Slot pycarray_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the Array Objects")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_methods, CDataType_methods},
{Py_tp_init, PyCArrayType_init},
{Py_tp_clear, CDataType_clear},

// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};

static PyType_Spec pycarray_type_spec = {
.name = "_ctypes.PyCArrayType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycarray_type_slots,
};
Expand Down Expand Up @@ -2315,17 +2288,12 @@ static PyType_Slot pycsimple_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for the PyCSimpleType Objects")},
{Py_tp_methods, PyCSimpleType_methods},
{Py_tp_init, PyCSimpleType_init},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},

// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};

static PyType_Spec pycsimple_type_spec = {
.name = "_ctypes.PyCSimpleType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycsimple_type_slots,
};
Expand Down Expand Up @@ -2570,19 +2538,14 @@ PyCFuncPtrType_init(PyObject *self, PyObject *args, PyObject *kwds)

static PyType_Slot pycfuncptr_type_slots[] = {
{Py_tp_doc, PyDoc_STR("metatype for C function pointers")},
{Py_tp_traverse, CDataType_traverse},
{Py_tp_clear, CDataType_clear},
{Py_tp_methods, CDataType_methods},
{Py_tp_init, PyCFuncPtrType_init},

// Sequence protocol.
{Py_sq_repeat, CDataType_repeat},
{0, NULL},
};

static PyType_Spec pycfuncptr_type_spec = {
.name = "_ctypes.PyCFuncPtrType",
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = pycfuncptr_type_slots,
};
Expand Down
8 changes: 8 additions & 0 deletions Modules/_ctypes/ctypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ typedef struct {
PyObject *converters; /* tuple([t.from_param for t in argtypes]) */
PyObject *restype; /* CDataObject or NULL */
PyObject *checker;
PyObject *module;
int flags; /* calling convention and such */

/* pep3118 fields, pointers need PyMem_Free */
Expand All @@ -313,6 +314,7 @@ typedef struct {
} StgInfo;

extern int PyCStgInfo_clone(StgInfo *dst_info, StgInfo *src_info);
extern void ctype_clear_stginfo(StgInfo *info);

typedef int(* PPROC)(void);

Expand Down Expand Up @@ -481,6 +483,12 @@ PyStgInfo_Init(ctypes_state *state, PyTypeObject *type)
type->tp_name);
return NULL;
}
PyObject *module = PyType_GetModule(state->PyCType_Type);
if (!module) {
return NULL;
}
info->module = Py_NewRef(module);

info->initialized = 1;
return info;
}
2 changes: 2 additions & 0 deletions Modules/_ctypes/stgdict.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ PyCStgInfo_clone(StgInfo *dst_info, StgInfo *src_info)
{
Py_ssize_t size;

ctype_clear_stginfo(dst_info);
PyMem_Free(dst_info->ffi_type_pointer.elements);
PyMem_Free(dst_info->format);
dst_info->format = NULL;
Expand All @@ -39,6 +40,7 @@ PyCStgInfo_clone(StgInfo *dst_info, StgInfo *src_info)
Py_XINCREF(dst_info->converters);
Py_XINCREF(dst_info->restype);
Py_XINCREF(dst_info->checker);
Py_XINCREF(dst_info->module);

if (src_info->format) {
dst_info->format = PyMem_Malloc(strlen(src_info->format) + 1);
Expand Down