From 8bb0d9788c2010be1686834887f610bf77fe4962 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 2 Jan 2024 03:47:32 +0900 Subject: [PATCH 01/17] PyCSimpleType_new() -> init() --- Modules/_ctypes/_ctypes.c | 45 ++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index fc16b9176fd1c0..8c7e392bd41ecb 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2031,6 +2031,16 @@ PyCSimpleType_paramfunc(CDataObject *self) static PyObject * PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result = PyType_Type.tp_new(type, args, kwds); +#if 0 + printf("new: %p %p\n", type, result); +#endif + return result; +} + +static int +PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) { PyTypeObject *result; StgDictObject *stgdict; @@ -2042,20 +2052,21 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) /* create the new instance (which is a class, since we are a metatype!) */ - result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); - if (result == NULL) - return NULL; + result = (PyTypeObject *)self; // by PyType_Type.tp_new() + PyTypeObject *type = Py_TYPE(self); +#if 0 + printf("ini: %p %p\n\n", type, result); +#endif if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_type_), &proto) < 0) { - return NULL; + return -1; } if (!proto) { PyErr_SetString(PyExc_AttributeError, "class must define a '_type_' attribute"); error: Py_XDECREF(proto); - Py_DECREF(result); - return NULL; + return -1; } if (PyUnicode_Check(proto)) { proto_str = PyUnicode_AsUTF8AndSize(proto, &proto_len); @@ -2103,10 +2114,9 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) stgdict->format = _ctypes_alloc_format_string_for_type(proto_str[0], 0); #endif if (stgdict->format == NULL) { - Py_DECREF(result); Py_DECREF(proto); Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } stgdict->paramfunc = PyCSimpleType_paramfunc; @@ -2122,9 +2132,8 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) /* replace the class dict by our updated spam dict */ if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { - Py_DECREF(result); Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } Py_SETREF(result->tp_dict, (PyObject *)stgdict); @@ -2161,16 +2170,14 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) int x; meth = PyDescr_NewClassMethod(result, ml); if (!meth) { - Py_DECREF(result); - return NULL; + return -1; } x = PyDict_SetItemString(result->tp_dict, ml->ml_name, meth); Py_DECREF(meth); if (x == -1) { - Py_DECREF(result); - return NULL; + return -1; } } } @@ -2180,8 +2187,7 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) proto, fmt); StgDictObject *sw_dict; if (swapped == NULL) { - Py_DECREF(result); - return NULL; + return -1; } sw_dict = PyType_stgdict(swapped); #ifdef WORDS_BIGENDIAN @@ -2201,12 +2207,11 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) #endif Py_DECREF(swapped); if (PyErr_Occurred()) { - Py_DECREF(result); - return NULL; + return -1; } }; - return (PyObject *)result; + return 0; } /* @@ -2328,7 +2333,7 @@ PyTypeObject PyCSimpleType_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + (initproc)PyCSimpleType_init, /* tp_init */ 0, /* tp_alloc */ PyCSimpleType_new, /* tp_new */ 0, /* tp_free */ From 45795e475ff37f34d39c70ab2d9a799066ed4f73 Mon Sep 17 00:00:00 2001 From: neonene Date: Tue, 2 Jan 2024 04:35:58 +0900 Subject: [PATCH 02/17] Make Simple_Type a heap type --- Modules/_ctypes/_ctypes.c | 149 ++++++++++---------- Modules/_ctypes/ctypes.h | 1 + Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 3 files changed, 75 insertions(+), 76 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 8c7e392bd41ecb..74a1b3bcae05c9 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -135,8 +135,6 @@ PyObject *PyExc_ArgError = NULL; /* This dict maps ctypes types to POINTER types */ PyObject *_ctypes_ptrtype_cache = NULL; -static PyTypeObject Simple_Type; - /* a callable object used for unpickling: strong reference to _ctypes._unpickle() function */ static PyObject *_unpickle; @@ -2029,16 +2027,6 @@ PyCSimpleType_paramfunc(CDataObject *self) return parg; } -static PyObject * -PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result = PyType_Type.tp_new(type, args, kwds); -#if 0 - printf("new: %p %p\n", type, result); -#endif - return result; -} - static int PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) { @@ -2054,9 +2042,8 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) since we are a metatype!) */ result = (PyTypeObject *)self; // by PyType_Type.tp_new() PyTypeObject *type = Py_TYPE(self); -#if 0 - printf("ini: %p %p\n\n", type, result); -#endif + + ctypes_state *st = GLOBAL_STATE(); if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_type_), &proto) < 0) { return -1; @@ -2140,7 +2127,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) /* Install from_param class methods in ctypes base classes. Overrides the PyCSimpleType_from_param generic method. */ - if (result->tp_base == &Simple_Type) { + if (result->tp_base == st->Simple_Type) { switch (*proto_str) { case 'z': /* c_char_p */ ml = &c_char_p_method; @@ -2335,7 +2322,7 @@ PyTypeObject PyCSimpleType_Type = { 0, /* tp_dictoffset */ (initproc)PyCSimpleType_init, /* tp_init */ 0, /* tp_alloc */ - PyCSimpleType_new, /* tp_new */ + 0, /* tp_new */ 0, /* tp_free */ }; @@ -3047,9 +3034,10 @@ PyCData_AtAddress(PyObject *type, void *buf) int _ctypes_simple_instance(PyObject *obj) { PyTypeObject *type = (PyTypeObject *)obj; - - if (PyCSimpleTypeObject_Check(type)) - return type->tp_base != &Simple_Type; + ctypes_state *st = GLOBAL_STATE(); + if (PyCSimpleTypeObject_Check(type)) { + return type->tp_base != st->Simple_Type; + } return 0; } @@ -4982,26 +4970,14 @@ static int Simple_bool(CDataObject *self) return memcmp(self->b_ptr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", self->b_size); } -static PyNumberMethods Simple_as_number = { - 0, /* nb_add */ - 0, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - (inquiry)Simple_bool, /* nb_bool */ -}; - /* "%s(%s)" % (self.__class__.__name__, self.value) */ static PyObject * Simple_repr(CDataObject *self) { PyObject *val, *result; + ctypes_state *st = GLOBAL_STATE(); - if (Py_TYPE(self)->tp_base != &Simple_Type) { + if (Py_TYPE(self)->tp_base != st->Simple_Type) { return PyUnicode_FromFormat("<%s object at %p>", Py_TYPE(self)->tp_name, self); } @@ -5016,46 +4992,54 @@ Simple_repr(CDataObject *self) return result; } -static PyTypeObject Simple_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes._SimpleCData", - sizeof(CDataObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)&Simple_repr, /* tp_repr */ - &Simple_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &PyCData_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("XXX to be provided"), /* tp_doc */ - (traverseproc)PyCData_traverse, /* tp_traverse */ - (inquiry)PyCData_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Simple_methods, /* tp_methods */ - 0, /* tp_members */ - Simple_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Simple_init, /* tp_init */ - 0, /* tp_alloc */ - GenericPyCData_new, /* tp_new */ - 0, /* tp_free */ +static int +Simple_traverse(CDataObject *self, visitproc visit, void *arg) +{ + PyTypeObject *base = Py_TYPE(self)->tp_base; + if (!base || !PyType_HasFeature(base, Py_TPFLAGS_HEAPTYPE)) { + Py_VISIT(self); + } + return 0; +} + +static int +Simple_clear(CDataObject *self) +{ + PyCData_clear(self); + return 0; +} + +static void +Simple_dealloc(PyObject *self) { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + Simple_clear((CDataObject *)self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot simple_slots[] = { + {Py_tp_repr, Simple_repr}, + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + {Py_tp_methods, Simple_methods}, + {Py_tp_getset, Simple_getsets}, + {Py_tp_new, GenericPyCData_new}, + {Py_tp_init, Simple_init}, + {Py_tp_traverse, Simple_traverse}, + {Py_tp_clear, Simple_clear}, + {Py_tp_dealloc, Simple_dealloc}, + {Py_nb_bool, Simple_bool}, + {0, NULL}, +}; + +static PyType_Spec simple_spec = { + .name = "_ctypes._SimpleCData", + .basicsize = sizeof(CDataObject), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = simple_slots, }; /******************************************************************/ @@ -5679,6 +5663,19 @@ _ctypes_add_types(PyObject *mod) TP = (PyTypeObject *)type; \ } while (0) +#define MOD_ADD_HEAPTYPE(TP, SPEC, BASE, TP_TYPE) do { \ + PyObject *type = PyType_FromMetaclass(TP_TYPE, mod, SPEC, \ + (PyObject *)BASE); \ + if (type == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(mod, (PyTypeObject *)type) < 0) { \ + Py_DECREF(type); \ + return -1; \ + } \ + TP = (PyTypeObject *)type; \ +} while (0) + ctypes_state *st = GLOBAL_STATE(); /* Note: @@ -5711,7 +5708,8 @@ _ctypes_add_types(PyObject *mod) MOD_ADD_TYPE(&Union_Type, &UnionType_Type, &PyCData_Type); MOD_ADD_TYPE(&PyCPointer_Type, &PyCPointerType_Type, &PyCData_Type); MOD_ADD_TYPE(&PyCArray_Type, &PyCArrayType_Type, &PyCData_Type); - MOD_ADD_TYPE(&Simple_Type, &PyCSimpleType_Type, &PyCData_Type); + MOD_ADD_HEAPTYPE(st->Simple_Type, &simple_spec, &PyCData_Type, + &PyCSimpleType_Type); MOD_ADD_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type, &PyCData_Type); /************************************************* @@ -5737,6 +5735,7 @@ _ctypes_add_types(PyObject *mod) #undef TYPE_READY_BASE #undef MOD_ADD_TYPE #undef CREATE_TYPE +#undef MOD_ADD_HEAPTYPE return 0; } diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 8891a0a741de7b..fa2b09a6f94fd7 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -41,6 +41,7 @@ typedef struct { PyTypeObject *PyComError_Type; #endif PyTypeObject *StructParam_Type; + PyTypeObject *Simple_Type; } ctypes_state; extern ctypes_state global_state; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index e3a1b5d532bda2..dc0182d9aadb5d 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -355,7 +355,6 @@ Modules/_ctypes/_ctypes.c - PyCPointerType_Type - Modules/_ctypes/_ctypes.c - PyCPointer_Type - Modules/_ctypes/_ctypes.c - PyCSimpleType_Type - Modules/_ctypes/_ctypes.c - PyCStructType_Type - -Modules/_ctypes/_ctypes.c - Simple_Type - Modules/_ctypes/_ctypes.c - Struct_Type - Modules/_ctypes/_ctypes.c - UnionType_Type - Modules/_ctypes/_ctypes.c - Union_Type - From 550e467f9dbf1787ddfea6d2604b62102247ce46 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 2 Jan 2024 15:57:56 +0900 Subject: [PATCH 03/17] reconsider Simple_traverse() --- Modules/_ctypes/_ctypes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 74a1b3bcae05c9..bad8aa4348c1fc 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4996,7 +4996,7 @@ static int Simple_traverse(CDataObject *self, visitproc visit, void *arg) { PyTypeObject *base = Py_TYPE(self)->tp_base; - if (!base || !PyType_HasFeature(base, Py_TPFLAGS_HEAPTYPE)) { + if (0) { // Fixme Py_VISIT(self); } return 0; From 6f005f4947f92368b382399442530d0fc22a4611 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 2 Jan 2024 17:25:58 +0900 Subject: [PATCH 04/17] warning --- Modules/_ctypes/_ctypes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index bad8aa4348c1fc..1cffdb458ceb37 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4995,8 +4995,8 @@ Simple_repr(CDataObject *self) static int Simple_traverse(CDataObject *self, visitproc visit, void *arg) { - PyTypeObject *base = Py_TYPE(self)->tp_base; - if (0) { // Fixme + if (0) { + // FIXME: avoid a crash Py_VISIT(self); } return 0; From ae9e2f589739d810b45c73ad5bf484d8e7f4f129 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 2 Jan 2024 20:10:14 +0900 Subject: [PATCH 05/17] non-fix edit --- Modules/_ctypes/_ctypes.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 1cffdb458ceb37..cb0b0a850ab3bb 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4999,14 +4999,13 @@ Simple_traverse(CDataObject *self, visitproc visit, void *arg) // FIXME: avoid a crash Py_VISIT(self); } - return 0; + return PyCData_traverse(self, visit, arg);; } static int Simple_clear(CDataObject *self) { - PyCData_clear(self); - return 0; + return PyCData_clear(self); } static void From 68d308b1c5ddb535b8c1ea7bdf2448f00c83cf6b Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:23:13 +0900 Subject: [PATCH 06/17] fixes a critical typo --- Modules/_ctypes/_ctypes.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index cb0b0a850ab3bb..2b06a257103761 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4995,11 +4995,8 @@ Simple_repr(CDataObject *self) static int Simple_traverse(CDataObject *self, visitproc visit, void *arg) { - if (0) { - // FIXME: avoid a crash - Py_VISIT(self); - } - return PyCData_traverse(self, visit, arg);; + Py_VISIT(Py_TYPE(self)); + return PyCData_traverse(self, visit, arg); } static int From 282d5d4af2afe0c1e5c2aef4408e96a9b7f6cf0b Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:36:08 +0900 Subject: [PATCH 07/17] base check (for now) --- Modules/_ctypes/_ctypes.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 2b06a257103761..0dd8beb9eb9f7f 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -4992,10 +4992,13 @@ Simple_repr(CDataObject *self) return result; } + static int Simple_traverse(CDataObject *self, visitproc visit, void *arg) { - Py_VISIT(Py_TYPE(self)); + if (!PyType_HasFeature(&PyCData_Type, Py_TPFLAGS_HEAPTYPE)) { + Py_VISIT(Py_TYPE(self)); + } return PyCData_traverse(self, visit, arg); } From 525de82f7b76f2299b2e2880b2f411440f2dde82 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Tue, 2 Jan 2024 23:07:30 +0900 Subject: [PATCH 08/17] cleanup --- Modules/_ctypes/_ctypes.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 0dd8beb9eb9f7f..4b126ab62ce04b 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5002,17 +5002,11 @@ Simple_traverse(CDataObject *self, visitproc visit, void *arg) return PyCData_traverse(self, visit, arg); } -static int -Simple_clear(CDataObject *self) -{ - return PyCData_clear(self); -} - static void Simple_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); - Simple_clear((CDataObject *)self); + PyCData_clear((CDataObject *)self); tp->tp_free(self); Py_DECREF(tp); } @@ -5025,7 +5019,7 @@ static PyType_Slot simple_slots[] = { {Py_tp_new, GenericPyCData_new}, {Py_tp_init, Simple_init}, {Py_tp_traverse, Simple_traverse}, - {Py_tp_clear, Simple_clear}, + {Py_tp_clear, PyCData_clear}, {Py_tp_dealloc, Simple_dealloc}, {Py_nb_bool, Simple_bool}, {0, NULL}, From d92e896b7d5bbf3e6d64374d61586a82be35e431 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 3 Jan 2024 00:53:35 +0900 Subject: [PATCH 09/17] nit --- Modules/_ctypes/_ctypes.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 4b126ab62ce04b..1e80e54b0e61ed 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2041,7 +2041,6 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) /* create the new instance (which is a class, since we are a metatype!) */ result = (PyTypeObject *)self; // by PyType_Type.tp_new() - PyTypeObject *type = Py_TYPE(self); ctypes_state *st = GLOBAL_STATE(); @@ -2169,6 +2168,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) } } + PyTypeObject *type = Py_TYPE(self); if (type == &PyCSimpleType_Type && fmt->setfunc_swapped && fmt->getfunc_swapped) { PyObject *swapped = CreateSwappedType(type, args, kwds, proto, fmt); @@ -3035,6 +3035,7 @@ int _ctypes_simple_instance(PyObject *obj) { PyTypeObject *type = (PyTypeObject *)obj; ctypes_state *st = GLOBAL_STATE(); + if (PyCSimpleTypeObject_Check(type)) { return type->tp_base != st->Simple_Type; } @@ -5702,7 +5703,7 @@ _ctypes_add_types(PyObject *mod) MOD_ADD_TYPE(&PyCPointer_Type, &PyCPointerType_Type, &PyCData_Type); MOD_ADD_TYPE(&PyCArray_Type, &PyCArrayType_Type, &PyCData_Type); MOD_ADD_HEAPTYPE(st->Simple_Type, &simple_spec, &PyCData_Type, - &PyCSimpleType_Type); + &PyCSimpleType_Type); MOD_ADD_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type, &PyCData_Type); /************************************************* From b5c2b40d0daf95e0b893523380453c004c0b0c09 Mon Sep 17 00:00:00 2001 From: neonene Date: Thu, 4 Jan 2024 02:28:17 +0900 Subject: [PATCH 10/17] convert PyCData_Type family to heap types --- Modules/_ctypes/_ctypes.c | 748 ++++++++------------ Modules/_ctypes/callbacks.c | 3 +- Modules/_ctypes/callproc.c | 18 +- Modules/_ctypes/cfield.c | 6 +- Modules/_ctypes/ctypes.h | 20 +- Tools/c-analyzer/cpython/globals-to-fix.tsv | 10 - 6 files changed, 311 insertions(+), 494 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 1e80e54b0e61ed..26ae633d5f8368 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -504,8 +504,8 @@ StructUnionType_paramfunc(CDataObject *self) return parg; } -static PyObject * -StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isStruct) +static int +StructUnionType_init(PyObject *self, PyObject *args, PyObject *kwds, int isStruct) { PyTypeObject *result; PyObject *fields; @@ -513,23 +513,20 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt /* create the new instance (which is a class, since we are a metatype!) */ - result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); - if (!result) - return NULL; + result = (PyTypeObject *)self; // by PyType_Type.tp_new() /* keep this for bw compatibility */ int r = PyDict_Contains(result->tp_dict, &_Py_ID(_abstract_)); - if (r > 0) - return (PyObject *)result; + if (r > 0) { + return 0; + } if (r < 0) { - Py_DECREF(result); - return NULL; + return -1; } dict = (StgDictObject *)_PyObject_CallNoArgs((PyObject *)&PyCStgDict_Type); if (!dict) { - Py_DECREF(result); - return NULL; + return -1; } if (!isStruct) { dict->flags |= TYPEFLAG_HASUNION; @@ -537,58 +534,54 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt /* replace the class dict by our updated stgdict, which holds info about storage requirements of the instances */ if (-1 == PyDict_Update((PyObject *)dict, result->tp_dict)) { - Py_DECREF(result); Py_DECREF((PyObject *)dict); - return NULL; + return -1; } Py_SETREF(result->tp_dict, (PyObject *)dict); dict->format = _ctypes_alloc_format_string(NULL, "B"); if (dict->format == NULL) { - Py_DECREF(result); - return NULL; + return -1; } dict->paramfunc = StructUnionType_paramfunc; if (PyDict_GetItemRef((PyObject *)dict, &_Py_ID(_fields_), &fields) < 0) { - Py_DECREF(result); - return NULL; + return -1; } if (fields) { if (PyObject_SetAttr((PyObject *)result, &_Py_ID(_fields_), fields) < 0) { - Py_DECREF(result); Py_DECREF(fields); - return NULL; + return -1; } Py_DECREF(fields); - return (PyObject *)result; + return 0; } else { StgDictObject *basedict = PyType_stgdict((PyObject *)result->tp_base); - if (basedict == NULL) - return (PyObject *)result; + if (basedict == NULL) { + return 0; + } /* copy base dict */ if (-1 == PyCStgDict_clone(dict, basedict)) { - Py_DECREF(result); - return NULL; + return -1; } dict->flags &= ~DICTFLAG_FINAL; /* clear the 'final' flag in the subclass dict */ basedict->flags |= DICTFLAG_FINAL; /* set the 'final' flag in the baseclass dict */ - return (PyObject *)result; + return 0; } } -static PyObject * -PyCStructType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int +PyCStructType_init(PyObject *self, PyObject *args, PyObject *kwds) { - return StructUnionType_new(type, args, kwds, 1); + return StructUnionType_init(self, args, kwds, 1); } -static PyObject * -UnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int +UnionType_init(PyObject *self, PyObject *args, PyObject *kwds) { - return StructUnionType_new(type, args, kwds, 0); + return StructUnionType_init(self, args, kwds, 0); } PyDoc_STRVAR(from_address_doc, @@ -970,9 +963,9 @@ PyTypeObject PyCStructType_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + PyCStructType_init, /* tp_init */ 0, /* tp_alloc */ - PyCStructType_new, /* tp_new */ + 0, /* tp_new */ 0, /* tp_free */ }; @@ -1012,9 +1005,9 @@ static PyTypeObject UnionType_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + UnionType_init, /* tp_init */ 0, /* tp_alloc */ - UnionType_new, /* tp_new */ + 0, /* tp_new */ 0, /* tp_free */ }; @@ -1069,8 +1062,8 @@ PyCPointerType_paramfunc(CDataObject *self) return parg; } -static PyObject * -PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int +PyCPointerType_init(PyObject *self, PyObject *args, PyObject *kwds) { PyTypeObject *result; StgDictObject *stgdict; @@ -1079,16 +1072,18 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) typedict = PyTuple_GetItem(args, 2); - if (!typedict) - return NULL; + if (!typedict) { + return -1; + } /* stgdict items size, align, length contain info about pointers itself, stgdict->proto has info about the pointed to type! */ stgdict = (StgDictObject *)_PyObject_CallNoArgs( (PyObject *)&PyCStgDict_Type); - if (!stgdict) - return NULL; + if (!stgdict) { + return -1; + } stgdict->size = sizeof(void *); stgdict->align = _ctypes_get_fielddesc("P")->pffi_type->alignment; stgdict->length = 1; @@ -1098,7 +1093,7 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (PyDict_GetItemRef(typedict, &_Py_ID(_type_), &proto) < 0) { Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } if (proto) { StgDictObject *itemdict; @@ -1106,7 +1101,7 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (-1 == PyCPointerType_SetProto(stgdict, proto)) { Py_DECREF(proto); Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } itemdict = PyType_stgdict(proto); /* PyCPointerType_SetProto has verified proto has a stgdict. */ @@ -1127,27 +1122,22 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(proto); if (stgdict->format == NULL) { Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } } /* create the new instance (which is a class, since we are a metatype!) */ - result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); - if (result == NULL) { - Py_DECREF((PyObject *)stgdict); - return NULL; - } + result = (PyTypeObject *)self; // by PyType_Type.tp_new() /* replace the class dict by our updated spam dict */ if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { - Py_DECREF(result); Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } Py_SETREF(result->tp_dict, (PyObject *)stgdict); - return (PyObject *)result; + return 0; } @@ -1205,7 +1195,8 @@ PyCPointerType_from_param(PyObject *type, PyObject *value) break; } - if (PointerObject_Check(value) || ArrayObject_Check(value)) { + ctypes_state *st = GLOBAL_STATE(); + if (PointerObject_Check(st, value) || ArrayObject_Check(st, value)) { /* Array instances are also pointers when the item types are the same. */ @@ -1268,9 +1259,9 @@ PyTypeObject PyCPointerType_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + PyCPointerType_init, /* tp_init */ 0, /* tp_alloc */ - PyCPointerType_new, /* tp_new */ + 0, /* tp_new */ 0, /* tp_free */ }; @@ -1464,8 +1455,8 @@ PyCArrayType_paramfunc(CDataObject *self) return p; } -static PyObject * -PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int +PyCArrayType_init(PyObject *self, PyObject *args, PyObject *kwds) { PyTypeObject *result; StgDictObject *stgdict; @@ -1476,9 +1467,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) /* create the new instance (which is a class, since we are a metatype!) */ - result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); - if (result == NULL) - return NULL; + result = (PyTypeObject *)self; // by PyType_Type.tp_new() /* Initialize these variables to NULL so that we can simplify error handling by using Py_XDECREF. */ @@ -1596,12 +1585,11 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) goto error; } - return (PyObject *)result; + return 0; error: Py_XDECREF((PyObject*)stgdict); Py_XDECREF(type_attr); - Py_DECREF(result); - return NULL; + return -1; } PyTypeObject PyCArrayType_Type = { @@ -1640,9 +1628,9 @@ PyTypeObject PyCArrayType_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + PyCArrayType_init, /* tp_init */ 0, /* tp_alloc */ - PyCArrayType_new, /* tp_new */ + 0, /* tp_new */ 0, /* tp_free */ }; @@ -1690,7 +1678,8 @@ c_wchar_p_from_param(PyObject *type, PyObject *value) if (res) { return Py_NewRef(value); } - if (ArrayObject_Check(value) || PointerObject_Check(value)) { + ctypes_state *st = GLOBAL_STATE(); + if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) { /* c_wchar array instance or pointer(c_wchar(...)) */ StgDictObject *dt = PyObject_stgdict(value); StgDictObject *dict; @@ -1700,7 +1689,6 @@ c_wchar_p_from_param(PyObject *type, PyObject *value) return Py_NewRef(value); } } - ctypes_state *st = GLOBAL_STATE(); if (PyCArg_CheckExact(st, value)) { /* byref(c_char(...)) */ PyCArgObject *a = (PyCArgObject *)value; @@ -1754,7 +1742,8 @@ c_char_p_from_param(PyObject *type, PyObject *value) if (res) { return Py_NewRef(value); } - if (ArrayObject_Check(value) || PointerObject_Check(value)) { + ctypes_state *st = GLOBAL_STATE(); + if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) { /* c_char array instance or pointer(c_char(...)) */ StgDictObject *dt = PyObject_stgdict(value); StgDictObject *dict; @@ -1764,7 +1753,6 @@ c_char_p_from_param(PyObject *type, PyObject *value) return Py_NewRef(value); } } - ctypes_state *st = GLOBAL_STATE(); if (PyCArg_CheckExact(st, value)) { /* byref(c_char(...)) */ PyCArgObject *a = (PyCArgObject *)value; @@ -1860,13 +1848,13 @@ c_void_p_from_param(PyObject *type, PyObject *value) /* c_void_p instances */ return Py_NewRef(value); } + ctypes_state *st = GLOBAL_STATE(); /* ctypes array or pointer instance */ - if (ArrayObject_Check(value) || PointerObject_Check(value)) { + if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) { /* Any array or pointer is accepted */ return Py_NewRef(value); } /* byref(...) */ - ctypes_state *st = GLOBAL_STATE(); if (PyCArg_CheckExact(st, value)) { /* byref(c_xxx()) */ PyCArgObject *a = (PyCArgObject *)value; @@ -1875,7 +1863,7 @@ c_void_p_from_param(PyObject *type, PyObject *value) } } /* function pointer */ - if (PyCFuncPtrObject_Check(value)) { + if (PyCFuncPtrObject_Check(st, value)) { PyCArgObject *parg; PyCFuncPtrObject *func; func = (PyCFuncPtrObject *)value; @@ -1891,7 +1879,7 @@ c_void_p_from_param(PyObject *type, PyObject *value) } /* c_char_p, c_wchar_p */ stgd = PyObject_stgdict(value); - if (stgd && CDataObject_Check(value) && stgd->proto && PyUnicode_Check(stgd->proto)) { + if (stgd && CDataObject_Check(st, value) && stgd->proto && PyUnicode_Check(stgd->proto)) { PyCArgObject *parg; switch (PyUnicode_AsUTF8(stgd->proto)[0]) { @@ -2518,17 +2506,17 @@ PyCFuncPtrType_paramfunc(CDataObject *self) return parg; } -static PyObject * -PyCFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int +PyCFuncPtrType_init(PyObject *self, PyObject *args, PyObject *kwds) { PyTypeObject *result; StgDictObject *stgdict; stgdict = (StgDictObject *)_PyObject_CallNoArgs( (PyObject *)&PyCStgDict_Type); - if (!stgdict) - return NULL; - + if (!stgdict) { + return -1; + } stgdict->paramfunc = PyCFuncPtrType_paramfunc; /* We do NOT expose the function signature in the format string. It is impossible, generally, because the only requirement for the @@ -2539,32 +2527,26 @@ PyCFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) stgdict->format = _ctypes_alloc_format_string(NULL, "X{}"); if (stgdict->format == NULL) { Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } stgdict->flags |= TYPEFLAG_ISPOINTER; /* create the new instance (which is a class, since we are a metatype!) */ - result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); - if (result == NULL) { - Py_DECREF((PyObject *)stgdict); - return NULL; - } + result = (PyTypeObject *)self; // by PyType_Type.tp_new() /* replace the class dict by our updated storage dict */ if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { - Py_DECREF(result); Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } Py_SETREF(result->tp_dict, (PyObject *)stgdict); if (-1 == make_funcptrtype_dict(stgdict)) { - Py_DECREF(result); - return NULL; + return -1; } - return (PyObject *)result; + return 0; } PyTypeObject PyCFuncPtrType_Type = { @@ -2603,9 +2585,9 @@ PyTypeObject PyCFuncPtrType_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + PyCFuncPtrType_init, /* tp_init */ 0, /* tp_alloc */ - PyCFuncPtrType_new, /* tp_new */ + 0, /* tp_new */ 0, /* tp_free */ }; @@ -2721,6 +2703,8 @@ KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep) static int PyCData_traverse(CDataObject *self, visitproc visit, void *arg) { + assert(PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)); + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->b_objects); Py_VISIT((PyObject *)self->b_base); return 0; @@ -2741,8 +2725,11 @@ PyCData_clear(CDataObject *self) static void PyCData_dealloc(PyObject *self) { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); PyCData_clear((CDataObject *)self); - Py_TYPE(self)->tp_free(self); + tp->tp_free(self); + Py_DECREF(tp); } static PyMemberDef PyCData_members[] = { @@ -2803,11 +2790,6 @@ PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags) return 0; } -static PyBufferProcs PyCData_as_buffer = { - PyCData_NewGetBuffer, - NULL, -}; - /* * CData objects are mutable, so they cannot be hashable! */ @@ -2886,46 +2868,27 @@ static PyMethodDef PyCData_methods[] = { { NULL, NULL }, }; -PyTypeObject PyCData_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes._CData", - sizeof(CDataObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - PyCData_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyCData_nohash, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &PyCData_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("XXX to be provided"), /* tp_doc */ - (traverseproc)PyCData_traverse, /* tp_traverse */ - (inquiry)PyCData_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyCData_methods, /* tp_methods */ - PyCData_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot pycdata_slots[] = { + {Py_tp_hash, PyCData_nohash}, + {Py_tp_dealloc, PyCData_dealloc}, + {Py_tp_traverse, PyCData_traverse}, + {Py_tp_clear, PyCData_clear}, + {Py_tp_methods, PyCData_methods}, + {Py_tp_members, PyCData_members}, + + // Buffer Protocol. + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + {0, NULL}, +}; + +static PyType_Spec pycdata_spec = { + .name = "_ctypes._CData", + .basicsize = sizeof(CDataObject), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = pycdata_slots, }; static int PyCData_MallocBuffer(CDataObject *obj, StgDictObject *dict) @@ -2973,12 +2936,14 @@ PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr) cmem = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); if (cmem == NULL) return NULL; - assert(CDataObject_Check(cmem)); - +#ifdef Py_DEBUG + ctypes_state *st = GLOBAL_STATE(); + assert(CDataObject_Check(st, cmem)); +#endif cmem->b_length = dict->length; cmem->b_size = dict->size; if (base) { /* use base's buffer */ - assert(CDataObject_Check(base)); + assert(CDataObject_Check(st, base)); cmem->b_ptr = adr; cmem->b_needsfree = 0; cmem->b_base = (CDataObject *)Py_NewRef(base); @@ -3019,7 +2984,10 @@ PyCData_AtAddress(PyObject *type, void *buf) pd = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); if (!pd) return NULL; - assert(CDataObject_Check(pd)); +#ifdef Py_DEBUG + ctypes_state *st = GLOBAL_STATE(); + assert(CDataObject_Check(st, pd)); +#endif pd->b_ptr = (char *)buf; pd->b_length = dict->length; pd->b_size = dict->size; @@ -3066,10 +3034,11 @@ _PyCData_set(CDataObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, CDataObject *src; int err; - if (setfunc) + if (setfunc) { return setfunc(ptr, value, size); - - if (!CDataObject_Check(value)) { + } + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, value)) { StgDictObject *dict = PyType_stgdict(type); if (dict && dict->setfunc) return dict->setfunc(ptr, value, size); @@ -3124,7 +3093,7 @@ _PyCData_set(CDataObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, } if (PyCPointerTypeObject_Check(type) - && ArrayObject_Check(value)) { + && ArrayObject_Check(st, value)) { StgDictObject *p1, *p2; PyObject *keep; p1 = PyObject_stgdict(value); @@ -3172,8 +3141,9 @@ PyCData_set(PyObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, { CDataObject *mem = (CDataObject *)dst; PyObject *result; + ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(dst)) { + if (!CDataObject_Check(st, dst)) { PyErr_SetString(PyExc_TypeError, "not a ctype instance"); return -1; @@ -3768,7 +3738,9 @@ static PyObject * _byref(PyObject *obj) { PyCArgObject *parg; - if (!CDataObject_Check(obj)) { + ctypes_state *st = GLOBAL_STATE(); + + if (!CDataObject_Check(st, obj)) { PyErr_SetString(PyExc_TypeError, "expected CData instance"); return NULL; @@ -4103,7 +4075,8 @@ PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds) "native com method call without 'this' parameter"); return NULL; } - if (!CDataObject_Check(this)) { + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, this)) { PyErr_SetString(PyExc_TypeError, "Expected a COM this pointer as first argument"); return NULL; @@ -4226,8 +4199,11 @@ PyCFuncPtr_clear(PyCFuncPtrObject *self) static void PyCFuncPtr_dealloc(PyCFuncPtrObject *self) { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); PyCFuncPtr_clear(self); - Py_TYPE(self)->tp_free((PyObject *)self); + tp->tp_free(self); + Py_DECREF(tp); } static PyObject * @@ -4255,59 +4231,32 @@ PyCFuncPtr_bool(PyCFuncPtrObject *self) ); } -static PyNumberMethods PyCFuncPtr_as_number = { - 0, /* nb_add */ - 0, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - (inquiry)PyCFuncPtr_bool, /* nb_bool */ +static PyType_Slot pycfuncptr_slots[] = { + {Py_tp_doc, PyDoc_STR("Function Pointer")}, + {Py_tp_repr, PyCFuncPtr_repr}, + {Py_tp_call, PyCFuncPtr_call}, + {Py_tp_dealloc, PyCFuncPtr_dealloc}, + {Py_tp_traverse, PyCFuncPtr_traverse}, + {Py_tp_clear, PyCFuncPtr_clear}, + {Py_tp_getset, PyCFuncPtr_getsets}, + {Py_tp_new, PyCFuncPtr_new}, + + // Buffer Protocol. + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + + // Number Protocol. + {Py_nb_bool, PyCFuncPtr_bool}, + {0, NULL}, }; -PyTypeObject PyCFuncPtr_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes.CFuncPtr", - sizeof(PyCFuncPtrObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)PyCFuncPtr_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)PyCFuncPtr_repr, /* tp_repr */ - &PyCFuncPtr_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)PyCFuncPtr_call, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &PyCData_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("Function Pointer"), /* tp_doc */ - (traverseproc)PyCFuncPtr_traverse, /* tp_traverse */ - (inquiry)PyCFuncPtr_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - PyCFuncPtr_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PyCFuncPtr_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec pycfuncptr_spec = { + .name = "_ctypes.CFuncPtr", + .basicsize = sizeof(PyCFuncPtrObject), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = pycfuncptr_slots, }; /*****************************************************************/ @@ -4419,88 +4368,50 @@ Struct_init(PyObject *self, PyObject *args, PyObject *kwds) return 0; } -static PyTypeObject Struct_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes.Structure", - sizeof(CDataObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &PyCData_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("Structure base class"), /* tp_doc */ - (traverseproc)PyCData_traverse, /* tp_traverse */ - (inquiry)PyCData_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - Struct_init, /* tp_init */ - 0, /* tp_alloc */ - GenericPyCData_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot struct_slots[] = { + {Py_tp_doc, PyDoc_STR("Structure base class")}, + {Py_tp_dealloc, PyCData_dealloc}, + {Py_tp_traverse, PyCData_traverse}, + {Py_tp_clear, PyCData_clear}, + {Py_tp_init, Struct_init}, + {Py_tp_new, GenericPyCData_new}, + + // Buffer Protocol. + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + {0, NULL}, }; -static PyTypeObject Union_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes.Union", - sizeof(CDataObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &PyCData_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("Union base class"), /* tp_doc */ - (traverseproc)PyCData_traverse, /* tp_traverse */ - (inquiry)PyCData_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - Struct_init, /* tp_init */ - 0, /* tp_alloc */ - GenericPyCData_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec struct_spec = { + .name = "_ctypes.Structure", + .basicsize = sizeof(CDataObject), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = struct_slots, +}; + +static PyType_Slot union_slots[] = { + {Py_tp_doc, PyDoc_STR("Union base class")}, + {Py_tp_dealloc, PyCData_dealloc}, + {Py_tp_traverse, PyCData_traverse}, + {Py_tp_clear, PyCData_clear}, + {Py_tp_init, Struct_init}, + {Py_tp_new, GenericPyCData_new}, + + // Buffer Protocol. + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + {0, NULL}, +}; + +static PyType_Spec union_spec = { + .name = "_ctypes.Union", + .basicsize = sizeof(CDataObject), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = union_slots, }; @@ -4761,26 +4672,6 @@ static PyMethodDef Array_methods[] = { { NULL, NULL } }; -static PySequenceMethods Array_as_sequence = { - Array_length, /* sq_length; */ - 0, /* sq_concat; */ - 0, /* sq_repeat; */ - Array_item, /* sq_item; */ - 0, /* sq_slice; */ - Array_ass_item, /* sq_ass_item; */ - 0, /* sq_ass_slice; */ - 0, /* sq_contains; */ - - 0, /* sq_inplace_concat; */ - 0, /* sq_inplace_repeat; */ -}; - -static PyMappingMethods Array_as_mapping = { - Array_length, - Array_subscript, - Array_ass_subscript, -}; - PyDoc_STRVAR(array_doc, "Abstract base class for arrays.\n" "\n" @@ -4791,46 +4682,38 @@ PyDoc_STRVAR(array_doc, "reads, the resulting object is not itself an Array." ); -PyTypeObject PyCArray_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes.Array", - sizeof(CDataObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &Array_as_sequence, /* tp_as_sequence */ - &Array_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &PyCData_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - array_doc, /* tp_doc */ - (traverseproc)PyCData_traverse, /* tp_traverse */ - (inquiry)PyCData_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Array_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Array_init, /* tp_init */ - 0, /* tp_alloc */ - GenericPyCData_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot array_slots[] = { + {Py_tp_doc, (void *)array_doc}, + {Py_tp_dealloc, PyCData_dealloc}, + {Py_tp_traverse, PyCData_traverse}, + {Py_tp_clear, PyCData_clear}, + {Py_tp_methods, Array_methods}, + {Py_tp_init, Array_init}, + {Py_tp_new, GenericPyCData_new}, + + // Buffer Protocol. + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + + // Mapping protocol + {Py_mp_length, Array_length}, + {Py_mp_subscript, Array_subscript}, + {Py_mp_ass_subscript, Array_ass_subscript}, + + // Sequence protocol. + {Py_sq_length, Array_length}, + {Py_sq_item, Array_item}, + {Py_sq_ass_item, Array_ass_item}, + {0, NULL}, +}; + +static PyType_Spec array_spec = { + .name = "_ctypes.Array", + .basicsize = sizeof(CDataObject), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = array_slots, }; PyObject * @@ -4874,11 +4757,11 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length) sprintf(name, "%.200s_Array_%ld", ((PyTypeObject *)itemtype)->tp_name, (long)length); #endif - + ctypes_state *st = GLOBAL_STATE(); result = PyObject_CallFunction((PyObject *)&PyCArrayType_Type, "s(O){s:n,s:O}", name, - &PyCArray_Type, + st->PyCArray_Type, "_length_", length, "_type_", @@ -4994,34 +4877,20 @@ Simple_repr(CDataObject *self) } -static int -Simple_traverse(CDataObject *self, visitproc visit, void *arg) -{ - if (!PyType_HasFeature(&PyCData_Type, Py_TPFLAGS_HEAPTYPE)) { - Py_VISIT(Py_TYPE(self)); - } - return PyCData_traverse(self, visit, arg); -} - -static void -Simple_dealloc(PyObject *self) { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - PyCData_clear((CDataObject *)self); - tp->tp_free(self); - Py_DECREF(tp); -} - static PyType_Slot simple_slots[] = { {Py_tp_repr, Simple_repr}, - {Py_bf_getbuffer, PyCData_NewGetBuffer}, + {Py_tp_dealloc, PyCData_dealloc}, + {Py_tp_traverse, PyCData_traverse}, + {Py_tp_clear, PyCData_clear}, {Py_tp_methods, Simple_methods}, {Py_tp_getset, Simple_getsets}, - {Py_tp_new, GenericPyCData_new}, {Py_tp_init, Simple_init}, - {Py_tp_traverse, Simple_traverse}, - {Py_tp_clear, PyCData_clear}, - {Py_tp_dealloc, Simple_dealloc}, + {Py_tp_new, GenericPyCData_new}, + + // Buffer Protocol. + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + + // Number Protocol. {Py_nb_bool, Simple_bool}, {0, NULL}, }; @@ -5142,7 +5011,8 @@ Pointer_set_contents(CDataObject *self, PyObject *value, void *closure) stgdict = PyObject_stgdict((PyObject *)self); assert(stgdict); /* Cannot be NULL for pointer instances */ assert(stgdict->proto); - if (!CDataObject_Check(value)) { + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, value)) { int res = PyObject_IsInstance(value, stgdict->proto); if (res == -1) return -1; @@ -5338,84 +5208,43 @@ Pointer_subscript(PyObject *myself, PyObject *item) } } -static PySequenceMethods Pointer_as_sequence = { - 0, /* inquiry sq_length; */ - 0, /* binaryfunc sq_concat; */ - 0, /* intargfunc sq_repeat; */ - Pointer_item, /* intargfunc sq_item; */ - 0, /* intintargfunc sq_slice; */ - Pointer_ass_item, /* intobjargproc sq_ass_item; */ - 0, /* intintobjargproc sq_ass_slice; */ - 0, /* objobjproc sq_contains; */ - /* Added in release 2.0 */ - 0, /* binaryfunc sq_inplace_concat; */ - 0, /* intargfunc sq_inplace_repeat; */ -}; - -static PyMappingMethods Pointer_as_mapping = { - 0, - Pointer_subscript, -}; - static int Pointer_bool(CDataObject *self) { return (*(void **)self->b_ptr != NULL); } -static PyNumberMethods Pointer_as_number = { - 0, /* nb_add */ - 0, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - (inquiry)Pointer_bool, /* nb_bool */ +static PyType_Slot pointer_slots[] = { + {Py_tp_dealloc, PyCData_dealloc}, + {Py_tp_traverse, PyCData_traverse}, + {Py_tp_clear, PyCData_clear}, + {Py_tp_getset, Pointer_getsets}, + {Py_tp_init, Pointer_init}, + {Py_tp_new, Pointer_new}, + + // Buffer Protocol. + {Py_bf_getbuffer, PyCData_NewGetBuffer}, + + // Mapping protocol. + {Py_mp_subscript, Pointer_subscript}, + + // Number Protocol. + {Py_nb_bool, Pointer_bool}, + + // Sequence protocol. + {Py_sq_item, Pointer_item}, + {Py_sq_ass_item, Pointer_ass_item}, + {0, NULL}, }; -PyTypeObject PyCPointer_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes._Pointer", - sizeof(CDataObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - &Pointer_as_number, /* tp_as_number */ - &Pointer_as_sequence, /* tp_as_sequence */ - &Pointer_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - &PyCData_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("XXX to be provided"), /* tp_doc */ - (traverseproc)PyCData_traverse, /* tp_traverse */ - (inquiry)PyCData_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - Pointer_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Pointer_init, /* tp_init */ - 0, /* tp_alloc */ - Pointer_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec pointer_spec = { + .name = "_ctypes._Pointer", + .basicsize = sizeof(CDataObject), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = pointer_slots, }; @@ -5561,7 +5390,8 @@ cast(void *ptr, PyObject *src, PyObject *ctype) It must certainly contain the source objects one. It must contain the source object itself. */ - if (CDataObject_Check(src)) { + ctypes_state *st = GLOBAL_STATE(); + if (CDataObject_Check(st, src)) { CDataObject *obj = (CDataObject *)src; CDataObject *container; @@ -5638,35 +5468,25 @@ _ctypes_add_types(PyObject *mod) TYPE_READY(type); \ } while (0) -#define MOD_ADD_TYPE(TYPE_EXPR, TP_TYPE, TP_BASE) \ - do { \ - PyTypeObject *type = (TYPE_EXPR); \ - Py_SET_TYPE(type, TP_TYPE); \ - type->tp_base = TP_BASE; \ - if (PyModule_AddType(mod, type) < 0) { \ - return -1; \ - } \ - } while (0) - -#define CREATE_TYPE(MOD, TP, SPEC, BASE) do { \ - PyObject *type = PyType_FromMetaclass(NULL, MOD, SPEC, \ - (PyObject *)BASE); \ +#define MOD_ADD_TYPE(TP, SPEC, TP_TYPE) do { \ + PyObject *type = PyType_FromMetaclass(TP_TYPE, mod, SPEC, \ + (PyObject *)st->PyCData_Type); \ if (type == NULL) { \ return -1; \ } \ + if (PyModule_AddType(mod, (PyTypeObject *)type) < 0) { \ + Py_DECREF(type); \ + return -1; \ + } \ TP = (PyTypeObject *)type; \ } while (0) -#define MOD_ADD_HEAPTYPE(TP, SPEC, BASE, TP_TYPE) do { \ - PyObject *type = PyType_FromMetaclass(TP_TYPE, mod, SPEC, \ +#define CREATE_TYPE(MOD, TP, SPEC, BASE) do { \ + PyObject *type = PyType_FromMetaclass(NULL, MOD, SPEC, \ (PyObject *)BASE); \ if (type == NULL) { \ return -1; \ } \ - if (PyModule_AddType(mod, (PyTypeObject *)type) < 0) { \ - Py_DECREF(type); \ - return -1; \ - } \ TP = (PyTypeObject *)type; \ } while (0) @@ -5678,7 +5498,7 @@ _ctypes_add_types(PyObject *mod) */ CREATE_TYPE(mod, st->PyCArg_Type, &carg_spec, NULL); CREATE_TYPE(mod, st->PyCThunk_Type, &cthunk_spec, NULL); - TYPE_READY(&PyCData_Type); + CREATE_TYPE(mod, st->PyCData_Type, &pycdata_spec, NULL); /* StgDict is derived from PyDict_Type */ TYPE_READY_BASE(&PyCStgDict_Type, &PyDict_Type); @@ -5698,13 +5518,12 @@ _ctypes_add_types(PyObject *mod) * Classes using a custom metaclass */ - MOD_ADD_TYPE(&Struct_Type, &PyCStructType_Type, &PyCData_Type); - MOD_ADD_TYPE(&Union_Type, &UnionType_Type, &PyCData_Type); - MOD_ADD_TYPE(&PyCPointer_Type, &PyCPointerType_Type, &PyCData_Type); - MOD_ADD_TYPE(&PyCArray_Type, &PyCArrayType_Type, &PyCData_Type); - MOD_ADD_HEAPTYPE(st->Simple_Type, &simple_spec, &PyCData_Type, - &PyCSimpleType_Type); - MOD_ADD_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type, &PyCData_Type); + MOD_ADD_TYPE(st->Struct_Type, &struct_spec, &PyCStructType_Type); + MOD_ADD_TYPE(st->Union_Type, &union_spec, &UnionType_Type); + MOD_ADD_TYPE(st->PyCPointer_Type, &pointer_spec, &PyCPointerType_Type); + MOD_ADD_TYPE(st->PyCArray_Type, &array_spec, &PyCArrayType_Type); + MOD_ADD_TYPE(st->Simple_Type, &simple_spec, &PyCSimpleType_Type); + MOD_ADD_TYPE(st->PyCFuncPtr_Type, &pycfuncptr_spec, &PyCFuncPtrType_Type); /************************************************* * @@ -5729,7 +5548,6 @@ _ctypes_add_types(PyObject *mod) #undef TYPE_READY_BASE #undef MOD_ADD_TYPE #undef CREATE_TYPE -#undef MOD_ADD_HEAPTYPE return 0; } diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 154e9f43983cdb..ef3f5f7dd49c44 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -175,7 +175,8 @@ static void _CallPythonObject(void *mem, PrintError("create argument %zd:\n", i); goto Done; } - if (!CDataObject_Check(obj)) { + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, obj)) { Py_DECREF(obj); PrintError("unexpected result of create argument %zd:\n", i); goto Done; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 3b11cd7f58ce4b..c4fca57064e67e 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1689,7 +1689,8 @@ sizeof_func(PyObject *self, PyObject *obj) if (dict) return PyLong_FromSsize_t(dict->size); - if (CDataObject_Check(obj)) + ctypes_state *st = GLOBAL_STATE(); + if (CDataObject_Check(st, obj)) return PyLong_FromSsize_t(((CDataObject *)obj)->b_size); PyErr_SetString(PyExc_TypeError, "this type has no size"); @@ -1744,7 +1745,8 @@ byref(PyObject *self, PyObject *args) if (offset == -1 && PyErr_Occurred()) return NULL; } - if (!CDataObject_Check(obj)) { + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, obj)) { PyErr_Format(PyExc_TypeError, "byref() argument must be a ctypes instance, not '%s'", Py_TYPE(obj)->tp_name); @@ -1769,7 +1771,8 @@ PyDoc_STRVAR(addressof_doc, static PyObject * addressof(PyObject *self, PyObject *obj) { - if (!CDataObject_Check(obj)) { + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, obj)) { PyErr_SetString(PyExc_TypeError, "invalid type"); return NULL; @@ -1925,13 +1928,14 @@ create_pointer_type(PyObject *module, PyObject *cls) // found or error return result; } + ctypes_state *st = GLOBAL_STATE(); // not found if (PyUnicode_CheckExact(cls)) { PyObject *name = PyUnicode_FromFormat("LP_%U", cls); - result = PyObject_CallFunction((PyObject *)Py_TYPE(&PyCPointer_Type), + result = PyObject_CallFunction((PyObject *)Py_TYPE(st->PyCPointer_Type), "N(O){}", name, - &PyCPointer_Type); + st->PyCPointer_Type); if (result == NULL) return result; key = PyLong_FromVoidPtr(result); @@ -1942,10 +1946,10 @@ create_pointer_type(PyObject *module, PyObject *cls) } else if (PyType_Check(cls)) { typ = (PyTypeObject *)cls; PyObject *name = PyUnicode_FromFormat("LP_%s", typ->tp_name); - result = PyObject_CallFunction((PyObject *)Py_TYPE(&PyCPointer_Type), + result = PyObject_CallFunction((PyObject *)Py_TYPE(st->PyCPointer_Type), "N(O){sO}", name, - &PyCPointer_Type, + st->PyCPointer_Type, "_type_", cls); if (result == NULL) return result; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index bfb40e5c5393fc..611165115ca3fa 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -204,7 +204,8 @@ PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value) { CDataObject *dst; char *ptr; - if (!CDataObject_Check(inst)) { + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, inst)) { PyErr_SetString(PyExc_TypeError, "not a ctype instance"); return -1; @@ -227,7 +228,8 @@ PyCField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type) if (inst == NULL) { return Py_NewRef(self); } - if (!CDataObject_Check(inst)) { + ctypes_state *st = GLOBAL_STATE(); + if (!CDataObject_Check(st, inst)) { PyErr_SetString(PyExc_TypeError, "not a ctype instance"); return NULL; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index fa2b09a6f94fd7..12f933bebc1ed9 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -41,7 +41,13 @@ typedef struct { PyTypeObject *PyComError_Type; #endif PyTypeObject *StructParam_Type; + PyTypeObject *PyCData_Type; + PyTypeObject *Struct_Type; + PyTypeObject *Union_Type; + PyTypeObject *PyCArray_Type; PyTypeObject *Simple_Type; + PyTypeObject *PyCPointer_Type; + PyTypeObject *PyCFuncPtr_Type; } ctypes_state; extern ctypes_state global_state; @@ -151,9 +157,8 @@ extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palig -extern PyTypeObject PyCData_Type; -#define CDataObject_CheckExact(v) Py_IS_TYPE(v, &PyCData_Type) -#define CDataObject_Check(v) PyObject_TypeCheck(v, &PyCData_Type) +#define CDataObject_CheckExact(st, v) Py_IS_TYPE((v), (st)->PyCData_Type) +#define CDataObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCData_Type) #define _CDataObject_HasExternalBuffer(v) ((v)->b_ptr != (char *)&(v)->b_value) extern PyTypeObject PyCSimpleType_Type; @@ -173,18 +178,15 @@ extern PyObject *PyCData_AtAddress(PyObject *type, void *buf); extern PyObject *PyCData_FromBytes(PyObject *type, char *data, Py_ssize_t length); extern PyTypeObject PyCArrayType_Type; -extern PyTypeObject PyCArray_Type; extern PyTypeObject PyCPointerType_Type; -extern PyTypeObject PyCPointer_Type; -extern PyTypeObject PyCFuncPtr_Type; extern PyTypeObject PyCFuncPtrType_Type; extern PyTypeObject PyCStructType_Type; #define PyCArrayTypeObject_Check(v) PyObject_TypeCheck(v, &PyCArrayType_Type) -#define ArrayObject_Check(v) PyObject_TypeCheck(v, &PyCArray_Type) -#define PointerObject_Check(v) PyObject_TypeCheck(v, &PyCPointer_Type) +#define ArrayObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCArray_Type) +#define PointerObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCPointer_Type) #define PyCPointerTypeObject_Check(v) PyObject_TypeCheck(v, &PyCPointerType_Type) -#define PyCFuncPtrObject_Check(v) PyObject_TypeCheck(v, &PyCFuncPtr_Type) +#define PyCFuncPtrObject_Check(st,v) PyObject_TypeCheck((v), (st)->PyCFuncPtr_Type) #define PyCFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, &PyCFuncPtrType_Type) #define PyCStructTypeObject_Check(v) PyObject_TypeCheck(v, &PyCStructType_Type) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index dc0182d9aadb5d..1eb60181107bd5 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -347,26 +347,16 @@ Modules/_testclinic.c - DeprKwdNew - ## static types Modules/_ctypes/_ctypes.c - PyCArrayType_Type - -Modules/_ctypes/_ctypes.c - PyCArray_Type - -Modules/_ctypes/_ctypes.c - PyCData_Type - Modules/_ctypes/_ctypes.c - PyCFuncPtrType_Type - -Modules/_ctypes/_ctypes.c - PyCFuncPtr_Type - Modules/_ctypes/_ctypes.c - PyCPointerType_Type - -Modules/_ctypes/_ctypes.c - PyCPointer_Type - Modules/_ctypes/_ctypes.c - PyCSimpleType_Type - Modules/_ctypes/_ctypes.c - PyCStructType_Type - -Modules/_ctypes/_ctypes.c - Struct_Type - Modules/_ctypes/_ctypes.c - UnionType_Type - -Modules/_ctypes/_ctypes.c - Union_Type - Modules/_ctypes/callproc.c - PyCArg_Type - Modules/_ctypes/ctypes.h - PyCArg_Type - Modules/_ctypes/ctypes.h - PyCArrayType_Type - -Modules/_ctypes/ctypes.h - PyCArray_Type - -Modules/_ctypes/ctypes.h - PyCData_Type - Modules/_ctypes/ctypes.h - PyCFuncPtrType_Type - -Modules/_ctypes/ctypes.h - PyCFuncPtr_Type - Modules/_ctypes/ctypes.h - PyCPointerType_Type - -Modules/_ctypes/ctypes.h - PyCPointer_Type - Modules/_ctypes/ctypes.h - PyCSimpleType_Type - Modules/_ctypes/ctypes.h - PyCStgDict_Type - Modules/_ctypes/ctypes.h - PyCStructType_Type - From 4a9dfe44d73790725a3d69644910c6e56d2ae070 Mon Sep 17 00:00:00 2001 From: neonene Date: Thu, 4 Jan 2024 04:48:52 +0900 Subject: [PATCH 11/17] CIFuzz friendly --- Modules/_ctypes/_ctypes.c | 18 +++++++----------- Modules/_ctypes/callbacks.c | 9 +++------ Modules/_ctypes/callproc.c | 7 ++++--- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 26ae633d5f8368..c3429c27fa2ead 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2934,16 +2934,14 @@ PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr) } dict->flags |= DICTFLAG_FINAL; cmem = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); - if (cmem == NULL) + if (cmem == NULL) { return NULL; -#ifdef Py_DEBUG - ctypes_state *st = GLOBAL_STATE(); - assert(CDataObject_Check(st, cmem)); -#endif + } + assert(CDataObject_Check(GLOBAL_STATE(), cmem)); cmem->b_length = dict->length; cmem->b_size = dict->size; if (base) { /* use base's buffer */ - assert(CDataObject_Check(st, base)); + assert(CDataObject_Check(GLOBAL_STATE(), base)); cmem->b_ptr = adr; cmem->b_needsfree = 0; cmem->b_base = (CDataObject *)Py_NewRef(base); @@ -2982,12 +2980,10 @@ PyCData_AtAddress(PyObject *type, void *buf) dict->flags |= DICTFLAG_FINAL; pd = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); - if (!pd) + if (!pd) { return NULL; -#ifdef Py_DEBUG - ctypes_state *st = GLOBAL_STATE(); - assert(CDataObject_Check(st, pd)); -#endif + } + assert(CDataObject_Check(GLOBAL_STATE(), pd)); pd->b_ptr = (char *)buf; pd->b_length = dict->length; pd->b_size = dict->size; diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index ef3f5f7dd49c44..2daf9b593d8c48 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -345,13 +345,10 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, assert(PyTuple_Check(converters)); nargs = PyTuple_GET_SIZE(converters); p = CThunkObject_new(nargs); - if (p == NULL) + if (p == NULL) { return NULL; - -#ifdef Py_DEBUG - ctypes_state *st = GLOBAL_STATE(); - assert(CThunk_CheckExact(st, (PyObject *)p)); -#endif + } + assert(CThunk_CheckExact(GLOBAL_STATE(), (PyObject *)p)); p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec); if (p->pcl_write == NULL) { diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index c4fca57064e67e..97d1dbaae03d4f 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1686,12 +1686,13 @@ sizeof_func(PyObject *self, PyObject *obj) StgDictObject *dict; dict = PyType_stgdict(obj); - if (dict) + if (dict) { return PyLong_FromSsize_t(dict->size); - + } ctypes_state *st = GLOBAL_STATE(); - if (CDataObject_Check(st, obj)) + if (CDataObject_Check(st, obj)) { return PyLong_FromSsize_t(((CDataObject *)obj)->b_size); + } PyErr_SetString(PyExc_TypeError, "this type has no size"); return NULL; From a1752d4a2cc5f45d09de5c2056e125bf5e5fa7f8 Mon Sep 17 00:00:00 2001 From: neonene Date: Sat, 6 Jan 2024 04:02:51 +0900 Subject: [PATCH 12/17] minor adjustments --- Modules/_ctypes/_ctypes.c | 7 ++++--- Modules/_ctypes/ctypes.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index c3429c27fa2ead..64030a3123792b 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -449,8 +449,8 @@ static PyType_Spec structparam_spec = { /* PyCStructType_Type - a meta type/class. Creating a new class using this one as - __metaclass__ will call the constructor StructUnionType_new. It replaces the - tp_dict member with a new instance of StgDict, and initializes the C + __metaclass__ will call the constructor StructUnionType_new/init. It replaces + the tp_dict member with a new instance of StgDict, and initializes the C accessible fields somehow. */ @@ -2715,8 +2715,9 @@ PyCData_clear(CDataObject *self) { Py_CLEAR(self->b_objects); if ((self->b_needsfree) - && _CDataObject_HasExternalBuffer(self)) + && _CDataObject_HasExternalBuffer(self)) { PyMem_Free(self->b_ptr); + } self->b_ptr = NULL; Py_CLEAR(self->b_base); return 0; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 12f933bebc1ed9..dc329f61407dfa 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -186,7 +186,7 @@ extern PyTypeObject PyCStructType_Type; #define ArrayObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCArray_Type) #define PointerObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCPointer_Type) #define PyCPointerTypeObject_Check(v) PyObject_TypeCheck(v, &PyCPointerType_Type) -#define PyCFuncPtrObject_Check(st,v) PyObject_TypeCheck((v), (st)->PyCFuncPtr_Type) +#define PyCFuncPtrObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCFuncPtr_Type) #define PyCFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, &PyCFuncPtrType_Type) #define PyCStructTypeObject_Check(v) PyObject_TypeCheck(v, &PyCStructType_Type) From 442194a9c8ff75d4270daac4d365fd386852ce97 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sat, 6 Jan 2024 19:01:55 +0900 Subject: [PATCH 13/17] drop heap type check --- Modules/_ctypes/_ctypes.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 64030a3123792b..d5e0a3ce757676 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2703,7 +2703,6 @@ KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep) static int PyCData_traverse(CDataObject *self, visitproc visit, void *arg) { - assert(PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)); Py_VISIT(Py_TYPE(self)); Py_VISIT(self->b_objects); Py_VISIT((PyObject *)self->b_base); From e817dc235928f2ee1ccf3c43ccfe10ee67cb19ed Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Fri, 19 Jan 2024 23:46:51 +0900 Subject: [PATCH 14/17] sync callbacks.c with main --- Modules/_ctypes/callbacks.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 2daf9b593d8c48..f70479435915ff 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -151,6 +151,7 @@ static void _CallPythonObject(void *mem, assert(nargs <= CTYPES_MAX_ARGCOUNT); PyObject **args = alloca(nargs * sizeof(PyObject *)); PyObject **cnvs = PySequence_Fast_ITEMS(converters); + ctypes_state *st = GLOBAL_STATE(); for (i = 0; i < nargs; i++) { PyObject *cnv = cnvs[i]; // borrowed ref StgDictObject *dict; @@ -175,7 +176,6 @@ static void _CallPythonObject(void *mem, PrintError("create argument %zd:\n", i); goto Done; } - ctypes_state *st = GLOBAL_STATE(); if (!CDataObject_Check(st, obj)) { Py_DECREF(obj); PrintError("unexpected result of create argument %zd:\n", i); @@ -345,10 +345,13 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, assert(PyTuple_Check(converters)); nargs = PyTuple_GET_SIZE(converters); p = CThunkObject_new(nargs); - if (p == NULL) { + if (p == NULL) return NULL; - } - assert(CThunk_CheckExact(GLOBAL_STATE(), (PyObject *)p)); + +#ifdef Py_DEBUG + ctypes_state *st = GLOBAL_STATE(); + assert(CThunk_CheckExact(st, (PyObject *)p)); +#endif p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec); if (p->pcl_write == NULL) { From 06f81a0eeb885382b00dbed3c5ae0a2183d468a8 Mon Sep 17 00:00:00 2001 From: neonene Date: Sun, 21 Jan 2024 23:37:57 +0900 Subject: [PATCH 15/17] reduce diff --- Modules/_ctypes/_ctypes.c | 84 +++++++++++++++---------------------- Modules/_ctypes/callbacks.c | 3 +- Modules/_ctypes/callproc.c | 14 +++---- Modules/_ctypes/cfield.c | 6 +-- Modules/_ctypes/ctypes.h | 10 ++--- 5 files changed, 46 insertions(+), 71 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 0a0b7c71005163..a47ede4982b6cb 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -517,9 +517,8 @@ StructUnionType_init(PyObject *self, PyObject *args, PyObject *kwds, int isStruc /* keep this for bw compatibility */ int r = PyDict_Contains(result->tp_dict, &_Py_ID(_abstract_)); - if (r > 0) { + if (r > 0) return 0; - } if (r < 0) { return -1; } @@ -1014,18 +1013,16 @@ PyCPointerType_init(PyObject *self, PyObject *args, PyObject *kwds) typedict = PyTuple_GetItem(args, 2); - if (!typedict) { + if (!typedict) return -1; - } /* stgdict items size, align, length contain info about pointers itself, stgdict->proto has info about the pointed to type! */ stgdict = (StgDictObject *)_PyObject_CallNoArgs( (PyObject *)&PyCStgDict_Type); - if (!stgdict) { + if (!stgdict) return -1; - } stgdict->size = sizeof(void *); stgdict->align = _ctypes_get_fielddesc("P")->pffi_type->alignment; stgdict->length = 1; @@ -1137,8 +1134,7 @@ PyCPointerType_from_param(PyObject *type, PyObject *value) break; } - ctypes_state *st = GLOBAL_STATE(); - if (PointerObject_Check(st, value) || ArrayObject_Check(st, value)) { + if (PointerObject_Check(value) || ArrayObject_Check(value)) { /* Array instances are also pointers when the item types are the same. */ @@ -1573,8 +1569,7 @@ c_wchar_p_from_param(PyObject *type, PyObject *value) if (res) { return Py_NewRef(value); } - ctypes_state *st = GLOBAL_STATE(); - if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) { + if (ArrayObject_Check(value) || PointerObject_Check(value)) { /* c_wchar array instance or pointer(c_wchar(...)) */ StgDictObject *dt = PyObject_stgdict(value); StgDictObject *dict; @@ -1584,6 +1579,7 @@ c_wchar_p_from_param(PyObject *type, PyObject *value) return Py_NewRef(value); } } + ctypes_state *st = GLOBAL_STATE(); if (PyCArg_CheckExact(st, value)) { /* byref(c_char(...)) */ PyCArgObject *a = (PyCArgObject *)value; @@ -1637,8 +1633,7 @@ c_char_p_from_param(PyObject *type, PyObject *value) if (res) { return Py_NewRef(value); } - ctypes_state *st = GLOBAL_STATE(); - if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) { + if (ArrayObject_Check(value) || PointerObject_Check(value)) { /* c_char array instance or pointer(c_char(...)) */ StgDictObject *dt = PyObject_stgdict(value); StgDictObject *dict; @@ -1648,6 +1643,7 @@ c_char_p_from_param(PyObject *type, PyObject *value) return Py_NewRef(value); } } + ctypes_state *st = GLOBAL_STATE(); if (PyCArg_CheckExact(st, value)) { /* byref(c_char(...)) */ PyCArgObject *a = (PyCArgObject *)value; @@ -1743,13 +1739,13 @@ c_void_p_from_param(PyObject *type, PyObject *value) /* c_void_p instances */ return Py_NewRef(value); } - ctypes_state *st = GLOBAL_STATE(); /* ctypes array or pointer instance */ - if (ArrayObject_Check(st, value) || PointerObject_Check(st, value)) { + if (ArrayObject_Check(value) || PointerObject_Check(value)) { /* Any array or pointer is accepted */ return Py_NewRef(value); } /* byref(...) */ + ctypes_state *st = GLOBAL_STATE(); if (PyCArg_CheckExact(st, value)) { /* byref(c_xxx()) */ PyCArgObject *a = (PyCArgObject *)value; @@ -1758,7 +1754,7 @@ c_void_p_from_param(PyObject *type, PyObject *value) } } /* function pointer */ - if (PyCFuncPtrObject_Check(st, value)) { + if (PyCFuncPtrObject_Check(value)) { PyCArgObject *parg; PyCFuncPtrObject *func; func = (PyCFuncPtrObject *)value; @@ -1774,11 +1770,7 @@ c_void_p_from_param(PyObject *type, PyObject *value) } /* c_char_p, c_wchar_p */ stgd = PyObject_stgdict(value); - if (stgd - && CDataObject_Check(st, value) - && stgd->proto - && PyUnicode_Check(stgd->proto)) - { + if (stgd && CDataObject_Check(value) && stgd->proto && PyUnicode_Check(stgd->proto)) { PyCArgObject *parg; switch (PyUnicode_AsUTF8(stgd->proto)[0]) { @@ -1968,7 +1960,6 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) goto error; } - ctypes_state *st = GLOBAL_STATE(); stgdict = (StgDictObject *)_PyObject_CallNoArgs( (PyObject *)&PyCStgDict_Type); if (!stgdict) @@ -1993,7 +1984,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) stgdict->paramfunc = PyCSimpleType_paramfunc; /* - if (result->tp_base != st->Simple_Type) { + if (result->tp_base != &Simple_Type) { stgdict->setfunc = NULL; stgdict->getfunc = NULL; } @@ -2012,6 +2003,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) /* Install from_param class methods in ctypes base classes. Overrides the PyCSimpleType_from_param generic method. */ + ctypes_state *st = GLOBAL_STATE(); if (result->tp_base == st->Simple_Type) { switch (*proto_str) { case 'z': /* c_char_p */ @@ -2392,9 +2384,9 @@ PyCFuncPtrType_init(PyObject *self, PyObject *args, PyObject *kwds) stgdict = (StgDictObject *)_PyObject_CallNoArgs( (PyObject *)&PyCStgDict_Type); - if (!stgdict) { + if (!stgdict) return -1; - } + stgdict->paramfunc = PyCFuncPtrType_paramfunc; /* We do NOT expose the function signature in the format string. It is impossible, generally, because the only requirement for the @@ -2786,14 +2778,14 @@ PyCData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr) } dict->flags |= DICTFLAG_FINAL; cmem = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); - if (cmem == NULL) { + if (cmem == NULL) return NULL; - } - assert(CDataObject_Check(GLOBAL_STATE(), cmem)); + assert(CDataObject_Check(cmem)); + cmem->b_length = dict->length; cmem->b_size = dict->size; if (base) { /* use base's buffer */ - assert(CDataObject_Check(GLOBAL_STATE(), base)); + assert(CDataObject_Check(base)); cmem->b_ptr = adr; cmem->b_needsfree = 0; cmem->b_base = (CDataObject *)Py_NewRef(base); @@ -2832,10 +2824,9 @@ PyCData_AtAddress(PyObject *type, void *buf) dict->flags |= DICTFLAG_FINAL; pd = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); - if (!pd) { + if (!pd) return NULL; - } - assert(CDataObject_Check(GLOBAL_STATE(), pd)); + assert(CDataObject_Check(pd)); pd->b_ptr = (char *)buf; pd->b_length = dict->length; pd->b_size = dict->size; @@ -2851,10 +2842,8 @@ int _ctypes_simple_instance(PyObject *obj) { PyTypeObject *type = (PyTypeObject *)obj; ctypes_state *st = GLOBAL_STATE(); - - if (PyCSimpleTypeObject_Check(type)) { + if (PyCSimpleTypeObject_Check(type)) return type->tp_base != st->Simple_Type; - } return 0; } @@ -2882,11 +2871,10 @@ _PyCData_set(CDataObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, CDataObject *src; int err; - if (setfunc) { + if (setfunc) return setfunc(ptr, value, size); - } - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, value)) { + + if (!CDataObject_Check(value)) { StgDictObject *dict = PyType_stgdict(type); if (dict && dict->setfunc) return dict->setfunc(ptr, value, size); @@ -2941,7 +2929,7 @@ _PyCData_set(CDataObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, } if (PyCPointerTypeObject_Check(type) - && ArrayObject_Check(st, value)) { + && ArrayObject_Check(value)) { StgDictObject *p1, *p2; PyObject *keep; p1 = PyObject_stgdict(value); @@ -2989,9 +2977,8 @@ PyCData_set(PyObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, { CDataObject *mem = (CDataObject *)dst; PyObject *result; - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, dst)) { + if (!CDataObject_Check(dst)) { PyErr_SetString(PyExc_TypeError, "not a ctype instance"); return -1; @@ -3586,9 +3573,7 @@ static PyObject * _byref(PyObject *obj) { PyCArgObject *parg; - ctypes_state *st = GLOBAL_STATE(); - - if (!CDataObject_Check(st, obj)) { + if (!CDataObject_Check(obj)) { PyErr_SetString(PyExc_TypeError, "expected CData instance"); return NULL; @@ -3923,8 +3908,7 @@ PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds) "native com method call without 'this' parameter"); return NULL; } - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, this)) { + if (!CDataObject_Check(this)) { PyErr_SetString(PyExc_TypeError, "Expected a COM this pointer as first argument"); return NULL; @@ -4597,6 +4581,7 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length) sprintf(name, "%.200s_Array_%ld", ((PyTypeObject *)itemtype)->tp_name, (long)length); #endif + ctypes_state *st = GLOBAL_STATE(); result = PyObject_CallFunction((PyObject *)st->PyCArrayType_Type, "s(O){s:n,s:O}", @@ -4700,7 +4685,6 @@ Simple_repr(CDataObject *self) { PyObject *val, *result; ctypes_state *st = GLOBAL_STATE(); - if (Py_TYPE(self)->tp_base != st->Simple_Type) { return PyUnicode_FromFormat("<%s object at %p>", Py_TYPE(self)->tp_name, self); @@ -4849,8 +4833,7 @@ Pointer_set_contents(CDataObject *self, PyObject *value, void *closure) stgdict = PyObject_stgdict((PyObject *)self); assert(stgdict); /* Cannot be NULL for pointer instances */ assert(stgdict->proto); - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, value)) { + if (!CDataObject_Check(value)) { int res = PyObject_IsInstance(value, stgdict->proto); if (res == -1) return -1; @@ -5226,8 +5209,7 @@ cast(void *ptr, PyObject *src, PyObject *ctype) It must certainly contain the source objects one. It must contain the source object itself. */ - ctypes_state *st = GLOBAL_STATE(); - if (CDataObject_Check(st, src)) { + if (CDataObject_Check(src)) { CDataObject *obj = (CDataObject *)src; CDataObject *container; diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index f70479435915ff..154e9f43983cdb 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -151,7 +151,6 @@ static void _CallPythonObject(void *mem, assert(nargs <= CTYPES_MAX_ARGCOUNT); PyObject **args = alloca(nargs * sizeof(PyObject *)); PyObject **cnvs = PySequence_Fast_ITEMS(converters); - ctypes_state *st = GLOBAL_STATE(); for (i = 0; i < nargs; i++) { PyObject *cnv = cnvs[i]; // borrowed ref StgDictObject *dict; @@ -176,7 +175,7 @@ static void _CallPythonObject(void *mem, PrintError("create argument %zd:\n", i); goto Done; } - if (!CDataObject_Check(st, obj)) { + if (!CDataObject_Check(obj)) { Py_DECREF(obj); PrintError("unexpected result of create argument %zd:\n", i); goto Done; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 97d1dbaae03d4f..7c5319ed3d845f 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1686,13 +1686,11 @@ sizeof_func(PyObject *self, PyObject *obj) StgDictObject *dict; dict = PyType_stgdict(obj); - if (dict) { + if (dict) return PyLong_FromSsize_t(dict->size); - } - ctypes_state *st = GLOBAL_STATE(); - if (CDataObject_Check(st, obj)) { + + if (CDataObject_Check(obj)) return PyLong_FromSsize_t(((CDataObject *)obj)->b_size); - } PyErr_SetString(PyExc_TypeError, "this type has no size"); return NULL; @@ -1746,8 +1744,7 @@ byref(PyObject *self, PyObject *args) if (offset == -1 && PyErr_Occurred()) return NULL; } - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, obj)) { + if (!CDataObject_Check(obj)) { PyErr_Format(PyExc_TypeError, "byref() argument must be a ctypes instance, not '%s'", Py_TYPE(obj)->tp_name); @@ -1772,8 +1769,7 @@ PyDoc_STRVAR(addressof_doc, static PyObject * addressof(PyObject *self, PyObject *obj) { - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, obj)) { + if (!CDataObject_Check(obj)) { PyErr_SetString(PyExc_TypeError, "invalid type"); return NULL; diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 611165115ca3fa..bfb40e5c5393fc 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -204,8 +204,7 @@ PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value) { CDataObject *dst; char *ptr; - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, inst)) { + if (!CDataObject_Check(inst)) { PyErr_SetString(PyExc_TypeError, "not a ctype instance"); return -1; @@ -228,8 +227,7 @@ PyCField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type) if (inst == NULL) { return Py_NewRef(self); } - ctypes_state *st = GLOBAL_STATE(); - if (!CDataObject_Check(st, inst)) { + if (!CDataObject_Check(inst)) { PyErr_SetString(PyExc_TypeError, "not a ctype instance"); return NULL; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 960d57c704c7f2..af6901c8cba584 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -162,8 +162,8 @@ extern int PyType_stginfo(PyTypeObject *self, Py_ssize_t *psize, Py_ssize_t *pal extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); -#define CDataObject_CheckExact(st, v) Py_IS_TYPE((v), (st)->PyCData_Type) -#define CDataObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCData_Type) +#define CDataObject_CheckExact(v) Py_IS_TYPE(v, GLOBAL_STATE()->PyCData_Type) +#define CDataObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCData_Type) #define _CDataObject_HasExternalBuffer(v) ((v)->b_ptr != (char *)&(v)->b_value) #define PyCSimpleTypeObject_CheckExact(v) Py_IS_TYPE(v, GLOBAL_STATE()->PyCSimpleType_Type) @@ -182,10 +182,10 @@ extern PyObject *PyCData_AtAddress(PyObject *type, void *buf); extern PyObject *PyCData_FromBytes(PyObject *type, char *data, Py_ssize_t length); #define PyCArrayTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCArrayType_Type) -#define ArrayObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCArray_Type) -#define PointerObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCPointer_Type) +#define ArrayObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCArray_Type) +#define PointerObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCPointer_Type) #define PyCPointerTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCPointerType_Type) -#define PyCFuncPtrObject_Check(st, v) PyObject_TypeCheck((v), (st)->PyCFuncPtr_Type) +#define PyCFuncPtrObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCFuncPtr_Type) #define PyCFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCFuncPtrType_Type) #define PyCStructTypeObject_Check(v) PyObject_TypeCheck(v, GLOBAL_STATE()->PyCStructType_Type) From 5354ffb0a66f9063a13ec097491e7f6b76b27d3f Mon Sep 17 00:00:00 2001 From: neonene Date: Sun, 21 Jan 2024 23:54:42 +0900 Subject: [PATCH 16/17] revert globals-to-fix.tsv --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 1eb60181107bd5..e3a1b5d532bda2 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -347,16 +347,27 @@ Modules/_testclinic.c - DeprKwdNew - ## static types Modules/_ctypes/_ctypes.c - PyCArrayType_Type - +Modules/_ctypes/_ctypes.c - PyCArray_Type - +Modules/_ctypes/_ctypes.c - PyCData_Type - Modules/_ctypes/_ctypes.c - PyCFuncPtrType_Type - +Modules/_ctypes/_ctypes.c - PyCFuncPtr_Type - Modules/_ctypes/_ctypes.c - PyCPointerType_Type - +Modules/_ctypes/_ctypes.c - PyCPointer_Type - Modules/_ctypes/_ctypes.c - PyCSimpleType_Type - Modules/_ctypes/_ctypes.c - PyCStructType_Type - +Modules/_ctypes/_ctypes.c - Simple_Type - +Modules/_ctypes/_ctypes.c - Struct_Type - Modules/_ctypes/_ctypes.c - UnionType_Type - +Modules/_ctypes/_ctypes.c - Union_Type - Modules/_ctypes/callproc.c - PyCArg_Type - Modules/_ctypes/ctypes.h - PyCArg_Type - Modules/_ctypes/ctypes.h - PyCArrayType_Type - +Modules/_ctypes/ctypes.h - PyCArray_Type - +Modules/_ctypes/ctypes.h - PyCData_Type - Modules/_ctypes/ctypes.h - PyCFuncPtrType_Type - +Modules/_ctypes/ctypes.h - PyCFuncPtr_Type - Modules/_ctypes/ctypes.h - PyCPointerType_Type - +Modules/_ctypes/ctypes.h - PyCPointer_Type - Modules/_ctypes/ctypes.h - PyCSimpleType_Type - Modules/_ctypes/ctypes.h - PyCStgDict_Type - Modules/_ctypes/ctypes.h - PyCStructType_Type - From 724f89320c1036878cdc3a771ba0c2ffff434e05 Mon Sep 17 00:00:00 2001 From: neonene Date: Mon, 22 Jan 2024 01:56:05 +0900 Subject: [PATCH 17/17] nit --- Modules/_ctypes/_ctypes.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index a47ede4982b6cb..b9d975f174b37f 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -558,9 +558,8 @@ StructUnionType_init(PyObject *self, PyObject *args, PyObject *kwds, int isStruc else { StgDictObject *basedict = PyType_stgdict((PyObject *)result->tp_base); - if (basedict == NULL) { + if (basedict == NULL) return 0; - } /* copy base dict */ if (-1 == PyCStgDict_clone(dict, basedict)) { return -1;