Mailing List Archive

gh-117142: Port _ctypes to multi-phase init (GH-117181)
https://github.com/python/cpython/commit/ef4118222b6d5f4532a2f1e234ba03955348d2a1
commit: ef4118222b6d5f4532a2f1e234ba03955348d2a1
branch: main
author: neonene <53406459+neonene@users.noreply.github.com>
committer: encukou <encukou@gmail.com>
date: 2024-04-10T11:00:01Z
summary:

gh-117142: Port _ctypes to multi-phase init (GH-117181)

files:
A Misc/NEWS.d/next/Library/2024-03-29-12-21-40.gh-issue-117142.U0agfh.rst
A Modules/_ctypes/clinic/_ctypes.c.h
M Lib/test/test_ctypes/test_refcounts.py
M Modules/_ctypes/_ctypes.c
M Modules/_ctypes/callbacks.c
M Modules/_ctypes/callproc.c
M Modules/_ctypes/cfield.c
M Modules/_ctypes/ctypes.h
M Modules/_ctypes/stgdict.c
M Tools/c-analyzer/cpython/ignored.tsv

diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py
index e6427d4a295b15..012722d8486218 100644
--- a/Lib/test/test_ctypes/test_refcounts.py
+++ b/Lib/test/test_ctypes/test_refcounts.py
@@ -4,6 +4,7 @@
import unittest
from test import support
from test.support import import_helper
+from test.support import script_helper
_ctypes_test = import_helper.import_module("_ctypes_test")


@@ -110,5 +111,18 @@ def func():
func()


+class ModuleIsolationTest(unittest.TestCase):
+ def test_finalize(self):
+ # check if gc_decref() succeeds
+ script = (
+ "import ctypes;"
+ "import sys;"
+ "del sys.modules['_ctypes'];"
+ "import _ctypes;"
+ "exit()"
+ )
+ script_helper.assert_python_ok("-c", script)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2024-03-29-12-21-40.gh-issue-117142.U0agfh.rst b/Misc/NEWS.d/next/Library/2024-03-29-12-21-40.gh-issue-117142.U0agfh.rst
new file mode 100644
index 00000000000000..36810bd815c502
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-03-29-12-21-40.gh-issue-117142.U0agfh.rst
@@ -0,0 +1 @@
+Convert :mod:`!_ctypes` to multi-phase initialisation (:pep:`489`).
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 631f82879311bf..3cb0b24668eb2a 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -126,8 +126,16 @@ bytes(cdata)

#include "pycore_long.h" // _PyLong_GetZero()

-ctypes_state global_state = {0};
+/*[clinic input]
+module _ctypes
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=476a19c49b31a75c]*/

+#define clinic_state() (get_module_state_by_class(cls))
+#define clinic_state_sub() (get_module_state_by_class(cls->tp_base))
+#include "clinic/_ctypes.c.h"
+#undef clinic_state
+#undef clinic_state_sub

/****************************************************************/

@@ -438,10 +446,15 @@ static PyType_Spec structparam_spec = {
CType_Type - a base metaclass. Its instances (classes) have a StgInfo.
*/

+/*[clinic input]
+class _ctypes.CType_Type "PyObject *" "clinic_state()->CType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8389fc5b74a84f2a]*/
+
static int
CType_Type_traverse(PyObject *self, visitproc visit, void *arg)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
if (st && st->PyCType_Type) {
StgInfo *info;
if (PyStgInfo_FromType(st, self, &info) < 0) {
@@ -475,7 +488,7 @@ ctype_clear_stginfo(StgInfo *info)
static int
CType_Type_clear(PyObject *self)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
if (st && st->PyCType_Type) {
StgInfo *info;
if (PyStgInfo_FromType(st, self, &info) < 0) {
@@ -491,8 +504,7 @@ CType_Type_clear(PyObject *self)
static void
CType_Type_dealloc(PyObject *self)
{
- ctypes_state *st = GLOBAL_STATE();
-
+ ctypes_state *st = get_module_state_by_def_final(Py_TYPE(self));
if (st && st->PyCType_Type) {
StgInfo *info;
if (PyStgInfo_FromType(st, self, &info) < 0) {
@@ -508,19 +520,27 @@ CType_Type_dealloc(PyObject *self)
ctype_clear_stginfo(info);
}
}
-
PyTypeObject *tp = Py_TYPE(self);
PyType_Type.tp_dealloc(self);
Py_DECREF(tp);
}

+/*[clinic input]
+_ctypes.CType_Type.__sizeof__
+
+ cls: defining_class
+ /
+Return memory consumption of the type object.
+[clinic start generated code]*/
+
static PyObject *
-CType_Type_sizeof(PyObject *self)
+_ctypes_CType_Type___sizeof___impl(PyObject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=c68c235be84d03f3 input=d064433b6110d1ce]*/
{
Py_ssize_t size = Py_TYPE(self)->tp_basicsize;
size += Py_TYPE(self)->tp_itemsize * Py_SIZE(self);

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
StgInfo *info;
if (PyStgInfo_FromType(st, self, &info) < 0) {
return NULL;
@@ -543,8 +563,7 @@ 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.")},
+ _CTYPES_CTYPE_TYPE___SIZEOF___METHODDEF
{0},
};

@@ -647,7 +666,7 @@ StructUnionType_init(PyObject *self, PyObject *args, PyObject *kwds, int isStruc
return -1;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
StgInfo *info = PyStgInfo_Init(st, (PyTypeObject *)self);
if (!info) {
Py_DECREF(attrdict);
@@ -710,11 +729,29 @@ UnionType_init(PyObject *self, PyObject *args, PyObject *kwds)
return StructUnionType_init(self, args, kwds, 0);
}

-PyDoc_STRVAR(from_address_doc,
-"C.from_address(integer) -> C instance\naccess a C instance at the specified address");
+/*[clinic input]
+class _ctypes.CDataType "PyObject *" "clinic_state()->CType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=466a505a93d73156]*/
+
+
+/*[clinic input]
+_ctypes.CDataType.from_address as CDataType_from_address
+
+ type: self
+ cls: defining_class
+ value: object
+ /
+
+C.from_address(integer) -> C instance
+
+Access a C instance at the specified address.
+[clinic start generated code]*/

static PyObject *
-CDataType_from_address(PyObject *type, PyObject *value)
+CDataType_from_address_impl(PyObject *type, PyTypeObject *cls,
+ PyObject *value)
+/*[clinic end generated code: output=5be4a7c0d9aa6c74 input=827a22cefe380c01]*/
{
void *buf;
if (!PyLong_Check(value)) {
@@ -725,26 +762,37 @@ CDataType_from_address(PyObject *type, PyObject *value)
buf = (void *)PyLong_AsVoidPtr(value);
if (PyErr_Occurred())
return NULL;
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
return PyCData_AtAddress(st, type, buf);
}

-PyDoc_STRVAR(from_buffer_doc,
-"C.from_buffer(object, offset=0) -> C instance\ncreate a C instance from a writeable buffer");
-
static int
KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep);

+/*[clinic input]
+_ctypes.CDataType.from_buffer as CDataType_from_buffer
+
+ type: self
+ cls: defining_class
+ obj: object
+ offset: Py_ssize_t = 0
+ /
+
+C.from_buffer(object, offset=0) -> C instance
+
+Create a C instance from a writeable buffer.
+[clinic start generated code]*/
+
static PyObject *
-CDataType_from_buffer(PyObject *type, PyObject *args)
+CDataType_from_buffer_impl(PyObject *type, PyTypeObject *cls, PyObject *obj,
+ Py_ssize_t offset)
+/*[clinic end generated code: output=57604e99635abd31 input=0f36cedd105ca28d]*/
{
- PyObject *obj;
PyObject *mv;
PyObject *result;
Py_buffer *buffer;
- Py_ssize_t offset = 0;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
StgInfo *info;
if (PyStgInfo_FromType(st, type, &info) < 0) {
return NULL;
@@ -754,9 +802,6 @@ CDataType_from_buffer(PyObject *type, PyObject *args)
return NULL;
}

- if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset))
- return NULL;
-
mv = PyMemoryView_FromObject(obj);
if (mv == NULL)
return NULL;
@@ -813,9 +858,6 @@ CDataType_from_buffer(PyObject *type, PyObject *args)
return result;
}

-PyDoc_STRVAR(from_buffer_copy_doc,
-"C.from_buffer_copy(object, offset=0) -> C instance\ncreate a C instance from a readable buffer");
-
static inline PyObject *
generic_pycdata_new(ctypes_state *st,
PyTypeObject *type, PyObject *args, PyObject *kwds);
@@ -823,14 +865,28 @@ generic_pycdata_new(ctypes_state *st,
static PyObject *
GenericPyCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds);

+/*[clinic input]
+_ctypes.CDataType.from_buffer_copy as CDataType_from_buffer_copy
+
+ type: self
+ cls: defining_class
+ buffer: Py_buffer
+ offset: Py_ssize_t = 0
+ /
+
+C.from_buffer_copy(object, offset=0) -> C instance
+
+Create a C instance from a readable buffer.
+[clinic start generated code]*/
+
static PyObject *
-CDataType_from_buffer_copy(PyObject *type, PyObject *args)
+CDataType_from_buffer_copy_impl(PyObject *type, PyTypeObject *cls,
+ Py_buffer *buffer, Py_ssize_t offset)
+/*[clinic end generated code: output=c8fc62b03e5cc6fa input=2a81e11b765a6253]*/
{
- Py_buffer buffer;
- Py_ssize_t offset = 0;
PyObject *result;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
StgInfo *info;
if (PyStgInfo_FromType(st, type, &info) < 0) {
return NULL;
@@ -840,54 +896,56 @@ CDataType_from_buffer_copy(PyObject *type, PyObject *args)
return NULL;
}

- if (!PyArg_ParseTuple(args, "y*|n:from_buffer_copy", &buffer, &offset))
- return NULL;
-
if (offset < 0) {
PyErr_SetString(PyExc_ValueError,
"offset cannot be negative");
- PyBuffer_Release(&buffer);
return NULL;
}

- if (info->size > buffer.len - offset) {
+ if (info->size > buffer->len - offset) {
PyErr_Format(PyExc_ValueError,
"Buffer size too small (%zd instead of at least %zd bytes)",
- buffer.len, info->size + offset);
- PyBuffer_Release(&buffer);
+ buffer->len, info->size + offset);
return NULL;
}

if (PySys_Audit("ctypes.cdata/buffer", "nnn",
- (Py_ssize_t)buffer.buf, buffer.len, offset) < 0) {
- PyBuffer_Release(&buffer);
+ (Py_ssize_t)buffer->buf, buffer->len, offset) < 0) {
return NULL;
}

result = generic_pycdata_new(st, (PyTypeObject *)type, NULL, NULL);
if (result != NULL) {
memcpy(((CDataObject *)result)->b_ptr,
- (char *)buffer.buf + offset, info->size);
+ (char *)buffer->buf + offset, info->size);
}
- PyBuffer_Release(&buffer);
return result;
}

-PyDoc_STRVAR(in_dll_doc,
-"C.in_dll(dll, name) -> C instance\naccess a C instance in a dll");
+/*[clinic input]
+_ctypes.CDataType.in_dll as CDataType_in_dll
+
+ type: self
+ cls: defining_class
+ dll: object
+ name: str
+ /
+
+C.in_dll(dll, name) -> C instance
+
+Access a C instance in a dll.
+[clinic start generated code]*/

static PyObject *
-CDataType_in_dll(PyObject *type, PyObject *args)
+CDataType_in_dll_impl(PyObject *type, PyTypeObject *cls, PyObject *dll,
+ const char *name)
+/*[clinic end generated code: output=d0e5c43b66bfa21f input=f85bf281477042b4]*/
{
- PyObject *dll;
- char *name;
PyObject *obj;
void *handle;
void *address;

- if (!PyArg_ParseTuple(args, "Os:in_dll", &dll, &name))
- return NULL;
- if (PySys_Audit("ctypes.dlsym", "O", args) < 0) {
+ if (PySys_Audit("ctypes.dlsym", "Os", dll, name) < 0) {
return NULL;
}

@@ -932,15 +990,24 @@ CDataType_in_dll(PyObject *type, PyObject *args)
return NULL;
}
#endif
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
return PyCData_AtAddress(st, type, address);
}

-PyDoc_STRVAR(from_param_doc,
-"Convert a Python object into a function call parameter.");
+/*[clinic input]
+_ctypes.CDataType.from_param as CDataType_from_param
+
+ type: self
+ cls: defining_class
+ value: object
+ /
+
+Convert a Python object into a function call parameter.
+[clinic start generated code]*/

static PyObject *
-CDataType_from_param(PyObject *type, PyObject *value)
+CDataType_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value)
+/*[clinic end generated code: output=8da9e34263309f9e input=275a52c4899ddff0]*/
{
PyObject *as_parameter;
int res = PyObject_IsInstance(value, type);
@@ -949,7 +1016,7 @@ CDataType_from_param(PyObject *type, PyObject *value)
if (res) {
return Py_NewRef(value);
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
if (PyCArg_CheckExact(st, value)) {
PyCArgObject *p = (PyCArgObject *)value;
PyObject *ob = p->obj;
@@ -979,7 +1046,7 @@ CDataType_from_param(PyObject *type, PyObject *value)
return NULL;
}
if (as_parameter) {
- value = CDataType_from_param(type, as_parameter);
+ value = CDataType_from_param_impl(type, cls, as_parameter);
Py_DECREF(as_parameter);
return value;
}
@@ -991,11 +1058,11 @@ CDataType_from_param(PyObject *type, PyObject *value)
}

static PyMethodDef CDataType_methods[] = {
- { "from_param", CDataType_from_param, METH_O, from_param_doc },
- { "from_address", CDataType_from_address, METH_O, from_address_doc },
- { "from_buffer", CDataType_from_buffer, METH_VARARGS, from_buffer_doc, },
- { "from_buffer_copy", CDataType_from_buffer_copy, METH_VARARGS, from_buffer_copy_doc, },
- { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc },
+ CDATATYPE_FROM_PARAM_METHODDEF
+ CDATATYPE_FROM_ADDRESS_METHODDEF
+ CDATATYPE_FROM_BUFFER_METHODDEF
+ CDATATYPE_FROM_BUFFER_COPY_METHODDEF
+ CDATATYPE_IN_DLL_METHODDEF
{ NULL, NULL },
};

@@ -1006,10 +1073,11 @@ CType_Type_repeat(PyObject *self, Py_ssize_t length)
return PyErr_Format(PyExc_ValueError,
"Array length must be >= 0, not %zd",
length);
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
return PyCArrayType_from_ctype(st, self, length);
}

+
static int
PyCStructType_setattro(PyObject *self, PyObject *key, PyObject *value)
{
@@ -1083,6 +1151,12 @@ size property/method, and the sequence protocol.

*/

+/*[clinic input]
+class _ctypes.PyCPointerType "PyObject *" "clinic_state()->PyCPointerType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c45e96c1f7645ab7]*/
+
+
static int
PyCPointerType_SetProto(ctypes_state *st, StgInfo *stginfo, PyObject *proto)
{
@@ -1136,7 +1210,7 @@ PyCPointerType_init(PyObject *self, PyObject *args, PyObject *kwds)
stginfo items size, align, length contain info about pointers itself,
stginfo->proto has info about the pointed to type!
*/
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject *)self);
if (!stginfo) {
return -1;
@@ -1186,15 +1260,25 @@ PyCPointerType_init(PyObject *self, PyObject *args, PyObject *kwds)
return 0;
}

+/*[clinic input]
+_ctypes.PyCPointerType.set_type as PyCPointerType_set_type
+
+ self: self(type="PyTypeObject *")
+ cls: defining_class
+ type: object
+ /
+[clinic start generated code]*/

static PyObject *
-PyCPointerType_set_type(PyTypeObject *self, PyObject *type)
+PyCPointerType_set_type_impl(PyTypeObject *self, PyTypeObject *cls,
+ PyObject *type)
+/*[clinic end generated code: output=51459d8f429a70ac input=67e1e8df921f123e]*/
{
PyObject *attrdict = PyType_GetDict(self);
if (!attrdict) {
return NULL;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)self, &info) < 0) {
Py_DECREF(attrdict);
@@ -1223,15 +1307,28 @@ PyCPointerType_set_type(PyTypeObject *self, PyObject *type)

static PyObject *_byref(ctypes_state *, PyObject *);

+/*[clinic input]
+_ctypes.PyCPointerType.from_param as PyCPointerType_from_param
+
+ type: self
+ cls: defining_class
+ value: object
+ /
+
+Convert a Python object into a function call parameter.
+[clinic start generated code]*/
+
static PyObject *
-PyCPointerType_from_param(PyObject *type, PyObject *value)
+PyCPointerType_from_param_impl(PyObject *type, PyTypeObject *cls,
+ PyObject *value)
+/*[clinic end generated code: output=a4b32d929aabaf64 input=6c231276e3997884]*/
{
if (value == Py_None) {
/* ConvParam will convert to a NULL pointer later */
return Py_NewRef(value);
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
StgInfo *typeinfo;
if (PyStgInfo_FromType(st, type, &typeinfo) < 0) {
return NULL;
@@ -1273,16 +1370,16 @@ PyCPointerType_from_param(PyObject *type, PyObject *value)
return Py_NewRef(value);
}
}
- return CDataType_from_param(type, value);
+ return CDataType_from_param_impl(type, cls, value);
}

static PyMethodDef PyCPointerType_methods[] = {
- { "from_address", CDataType_from_address, METH_O, from_address_doc },
- { "from_buffer", CDataType_from_buffer, METH_VARARGS, from_buffer_doc, },
- { "from_buffer_copy", CDataType_from_buffer_copy, METH_VARARGS, from_buffer_copy_doc, },
- { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc},
- { "from_param", (PyCFunction)PyCPointerType_from_param, METH_O, from_param_doc},
- { "set_type", (PyCFunction)PyCPointerType_set_type, METH_O },
+ CDATATYPE_FROM_ADDRESS_METHODDEF
+ CDATATYPE_FROM_BUFFER_METHODDEF
+ CDATATYPE_FROM_BUFFER_COPY_METHODDEF
+ CDATATYPE_IN_DLL_METHODDEF
+ PYCPOINTERTYPE_FROM_PARAM_METHODDEF
+ PYCPOINTERTYPE_SET_TYPE_METHODDEF
{ NULL, NULL },
};

@@ -1543,7 +1640,7 @@ PyCArrayType_init(PyObject *self, PyObject *args, PyObject *kwds)
goto error;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject*)self);
if (!stginfo) {
goto error;
@@ -1641,17 +1738,47 @@ _type_ attribute.

*/

+/*[clinic input]
+class _ctypes.PyCSimpleType "PyObject *" "clinic_state()->PyCSimpleType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d5a45772668e7f49]*/
+
+/*[clinic input]
+class _ctypes.c_wchar_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=468de7283d622d47]*/
+
+/*[clinic input]
+class _ctypes.c_char_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e750865616e7dcea]*/
+
+/*[clinic input]
+class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
+
static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g";

+/*[clinic input]
+_ctypes.c_wchar_p.from_param as c_wchar_p_from_param
+
+ type: self
+ cls: defining_class
+ value: object
+ /
+[clinic start generated code]*/
+
static PyObject *
-c_wchar_p_from_param(PyObject *type, PyObject *value)
+c_wchar_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value)
+/*[clinic end generated code: output=e453949a2f725a4c input=d322c7237a319607]*/
{
PyObject *as_parameter;
int res;
if (value == Py_None) {
Py_RETURN_NONE;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls->tp_base);
if (PyUnicode_Check(value)) {
PyCArgObject *parg;
struct fielddesc *fd = _ctypes_get_fielddesc("Z");
@@ -1707,7 +1834,7 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
return NULL;
}
if (as_parameter) {
- value = c_wchar_p_from_param(type, as_parameter);
+ value = c_wchar_p_from_param_impl(type, cls, as_parameter);
Py_DECREF(as_parameter);
return value;
}
@@ -1717,15 +1844,25 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
return NULL;
}

+/*[clinic input]
+_ctypes.c_char_p.from_param as c_char_p_from_param
+
+ type: self
+ cls: defining_class
+ value: object
+ /
+[clinic start generated code]*/
+
static PyObject *
-c_char_p_from_param(PyObject *type, PyObject *value)
+c_char_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value)
+/*[clinic end generated code: output=219652ab7c174aa1 input=6cf0d1b6bb4ede11]*/
{
PyObject *as_parameter;
int res;
if (value == Py_None) {
Py_RETURN_NONE;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls->tp_base);
if (PyBytes_Check(value)) {
PyCArgObject *parg;
struct fielddesc *fd = _ctypes_get_fielddesc("z");
@@ -1781,7 +1918,7 @@ c_char_p_from_param(PyObject *type, PyObject *value)
return NULL;
}
if (as_parameter) {
- value = c_char_p_from_param(type, as_parameter);
+ value = c_char_p_from_param_impl(type, cls, as_parameter);
Py_DECREF(as_parameter);
return value;
}
@@ -1791,8 +1928,18 @@ c_char_p_from_param(PyObject *type, PyObject *value)
return NULL;
}

+/*[clinic input]
+_ctypes.c_void_p.from_param as c_void_p_from_param
+
+ type: self
+ cls: defining_class
+ value: object
+ /
+[clinic start generated code]*/
+
static PyObject *
-c_void_p_from_param(PyObject *type, PyObject *value)
+c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value)
+/*[clinic end generated code: output=984d0075b6038cc7 input=0e8b343fc19c77d4]*/
{
PyObject *as_parameter;
int res;
@@ -1801,7 +1948,7 @@ c_void_p_from_param(PyObject *type, PyObject *value)
if (value == Py_None) {
Py_RETURN_NONE;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls->tp_base);

/* Should probably allow buffer interface as well */
/* int, long */
@@ -1923,7 +2070,7 @@ c_void_p_from_param(PyObject *type, PyObject *value)
return NULL;
}
if (as_parameter) {
- value = c_void_p_from_param(type, as_parameter);
+ value = c_void_p_from_param_impl(type, cls, as_parameter);
Py_DECREF(as_parameter);
return value;
}
@@ -1933,9 +2080,9 @@ c_void_p_from_param(PyObject *type, PyObject *value)
return NULL;
}

-static PyMethodDef c_void_p_method = { "from_param", c_void_p_from_param, METH_O };
-static PyMethodDef c_char_p_method = { "from_param", c_char_p_from_param, METH_O };
-static PyMethodDef c_wchar_p_method = { "from_param", c_wchar_p_from_param, METH_O };
+static PyMethodDef c_void_p_methods[] = {C_VOID_P_FROM_PARAM_METHODDEF {0}};
+static PyMethodDef c_char_p_methods[] = {C_CHAR_P_FROM_PARAM_METHODDEF {0}};
+static PyMethodDef c_wchar_p_methods[] = {C_WCHAR_P_FROM_PARAM_METHODDEF {0}};

static PyObject *CreateSwappedType(ctypes_state *st, PyTypeObject *type,
PyObject *args, PyObject *kwds,
@@ -2081,7 +2228,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
goto error;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject *)self);
if (!stginfo) {
goto error;
@@ -2120,15 +2267,15 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
if (((PyTypeObject *)self)->tp_base == st->Simple_Type) {
switch (*proto_str) {
case 'z': /* c_char_p */
- ml = &c_char_p_method;
+ ml = c_char_p_methods;
stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
case 'Z': /* c_wchar_p */
- ml = &c_wchar_p_method;
+ ml = c_wchar_p_methods;
stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
case 'P': /* c_void_p */
- ml = &c_void_p_method;
+ ml = c_void_p_methods;
stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
case 's':
@@ -2202,8 +2349,22 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
* This is a *class method*.
* Convert a parameter into something that ConvParam can handle.
*/
+
+/*[clinic input]
+_ctypes.PyCSimpleType.from_param as PyCSimpleType_from_param
+
+ type: self
+ cls: defining_class
+ value: object
+ /
+
+Convert a Python object into a function call parameter.
+[clinic start generated code]*/
+
static PyObject *
-PyCSimpleType_from_param(PyObject *type, PyObject *value)
+PyCSimpleType_from_param_impl(PyObject *type, PyTypeObject *cls,
+ PyObject *value)
+/*[clinic end generated code: output=8a8453d9663e3a2e input=61cc48ce3a87a570]*/
{
const char *fmt;
PyCArgObject *parg;
@@ -2220,7 +2381,7 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
return Py_NewRef(value);
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
StgInfo *info;
if (PyStgInfo_FromType(st, type, &info) < 0) {
return NULL;
@@ -2260,7 +2421,7 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
Py_XDECREF(exc);
return NULL;
}
- value = PyCSimpleType_from_param(type, as_parameter);
+ value = PyCSimpleType_from_param_impl(type, cls, as_parameter);
_Py_LeaveRecursiveCall();
Py_DECREF(as_parameter);
Py_XDECREF(exc);
@@ -2276,11 +2437,11 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
}

static PyMethodDef PyCSimpleType_methods[] = {
- { "from_param", PyCSimpleType_from_param, METH_O, from_param_doc },
- { "from_address", CDataType_from_address, METH_O, from_address_doc },
- { "from_buffer", CDataType_from_buffer, METH_VARARGS, from_buffer_doc, },
- { "from_buffer_copy", CDataType_from_buffer_copy, METH_VARARGS, from_buffer_copy_doc, },
- { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc},
+ PYCSIMPLETYPE_FROM_PARAM_METHODDEF
+ CDATATYPE_FROM_ADDRESS_METHODDEF
+ CDATATYPE_FROM_BUFFER_METHODDEF
+ CDATATYPE_FROM_BUFFER_COPY_METHODDEF
+ CDATATYPE_IN_DLL_METHODDEF
{ NULL, NULL },
};

@@ -2505,7 +2666,7 @@ PyCFuncPtrType_init(PyObject *self, PyObject *args, PyObject *kwds)
return -1;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(self));
StgInfo *stginfo = PyStgInfo_Init(st, (PyTypeObject *)self);
if (!stginfo) {
Py_DECREF(attrdict);
@@ -2659,6 +2820,13 @@ KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep)
/*
PyCData_Type
*/
+
+/*[clinic input]
+class _ctypes.PyCData "PyObject *" "clinic_state()->PyCData_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ac13df38dee3c22c]*/
+
+
static int
PyCData_traverse(CDataObject *self, visitproc visit, void *arg)
{
@@ -2731,7 +2899,7 @@ PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags)
{
CDataObject *self = (CDataObject *)myself;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself)));
StgInfo *info;
if (PyStgInfo_FromObject(st, myself, &info) < 0) {
return -1;
@@ -2776,12 +2944,21 @@ PyCData_nohash(PyObject *self)
return -1;
}

+/*[clinic input]
+_ctypes.PyCData.__reduce__ as PyCData_reduce
+
+ myself: self
+ cls: defining_class
+ /
+[clinic start generated code]*/
+
static PyObject *
-PyCData_reduce(PyObject *myself, PyObject *args)
+PyCData_reduce_impl(PyObject *myself, PyTypeObject *cls)
+/*[clinic end generated code: output=1a025ccfdd8c935d input=34097a5226ea63c1]*/
{
CDataObject *self = (CDataObject *)myself;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
StgInfo *info;
if (PyStgInfo_FromObject(st, myself, &info) < 0) {
return NULL;
@@ -2846,7 +3023,7 @@ PyCData_from_outparam(PyObject *self, PyObject *args)

static PyMethodDef PyCData_methods[] = {
{ "__ctypes_from_outparam__", PyCData_from_outparam, METH_NOARGS, },
- { "__reduce__", PyCData_reduce, METH_NOARGS, },
+ PYCDATA_REDUCE_METHODDEF
{ "__setstate__", PyCData_setstate, METH_VARARGS, },
{ NULL, NULL },
};
@@ -3161,7 +3338,7 @@ PyCData_set(ctypes_state *st,
static PyObject *
GenericPyCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
return generic_pycdata_new(st, type, args, kwds);
}

@@ -3236,7 +3413,7 @@ PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ign
Py_XDECREF(oldchecker);
return 0;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *info;
if (PyStgInfo_FromType(st, ob, &info) < 0) {
return -1;
@@ -3263,7 +3440,7 @@ PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
if (self->restype) {
return Py_NewRef(self->restype);
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *info;
if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
return NULL;
@@ -3285,7 +3462,7 @@ PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ig
Py_CLEAR(self->converters);
Py_CLEAR(self->argtypes);
} else {
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
converters = converters_from_argtypes(st, ob);
if (!converters)
return -1;
@@ -3302,7 +3479,7 @@ PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
if (self->argtypes) {
return Py_NewRef(self->argtypes);
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *info;
if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
return NULL;
@@ -3351,7 +3528,7 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type)
return NULL;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
return NULL;
@@ -3598,7 +3775,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
#endif
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
if (!_validate_paramflags(st, type, paramflags)) {
Py_DECREF(ftuple);
return NULL;
@@ -3640,7 +3817,7 @@ PyCFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (paramflags == Py_None)
paramflags = NULL;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
if (!_validate_paramflags(st, type, paramflags)) {
return NULL;
}
@@ -3721,7 +3898,7 @@ PyCFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
*/

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
return NULL;
@@ -4088,7 +4265,7 @@ PyCFuncPtr_call(PyCFuncPtrObject *self, PyObject *inargs, PyObject *kwds)
int outmask;
unsigned int numretvals;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *info;
if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
return NULL;
@@ -4312,7 +4489,7 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
PyObject *fields;
Py_ssize_t i;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
StgInfo *baseinfo;
if (PyStgInfo_FromType(st, (PyObject *)type->tp_base, &baseinfo) < 0) {
return -1;
@@ -4482,7 +4659,7 @@ Array_item(PyObject *myself, Py_ssize_t index)
return NULL;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return NULL;
@@ -4523,7 +4700,7 @@ Array_subscript(PyObject *myself, PyObject *item)
}
slicelen = PySlice_AdjustIndices(self->b_length, &start, &stop, step);

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return NULL;
@@ -4624,7 +4801,7 @@ Array_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
return -1;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return -1;
@@ -4815,6 +4992,12 @@ PyCArrayType_from_ctype(ctypes_state *st, PyObject *itemtype, Py_ssize_t length)
Simple_Type
*/

+/*[clinic input]
+class _ctypes.Simple "PyObject *" "clinic_state()->Simple_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=016c476c7aa8b8a8]*/
+
+
static int
Simple_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
@@ -4826,7 +5009,7 @@ Simple_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
return -1;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *info;
if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
return -1;
@@ -4856,7 +5039,7 @@ Simple_init(CDataObject *self, PyObject *args, PyObject *kw)
static PyObject *
Simple_get_value(CDataObject *self, void *Py_UNUSED(ignored))
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *info;
if (PyStgInfo_FromObject(st, (PyObject *)self, &info) < 0) {
return NULL;
@@ -4872,10 +5055,19 @@ static PyGetSetDef Simple_getsets[] = {
{ NULL, NULL }
};

+/*[clinic input]
+_ctypes.Simple.__ctypes_from_outparam__ as Simple_from_outparm
+
+ self: self
+ cls: defining_class
+ /
+[clinic start generated code]*/
+
static PyObject *
-Simple_from_outparm(PyObject *self, PyObject *args)
+Simple_from_outparm_impl(PyObject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=6c61d90da8aa9b4f input=0f362803fb4629d5]*/
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(cls);
if (_ctypes_simple_instance(st, (PyObject *)Py_TYPE(self))) {
return Py_NewRef(self);
}
@@ -4884,7 +5076,7 @@ Simple_from_outparm(PyObject *self, PyObject *args)
}

static PyMethodDef Simple_methods[] = {
- { "__ctypes_from_outparam__", Simple_from_outparm, METH_NOARGS, },
+ SIMPLE_FROM_OUTPARM_METHODDEF
{ NULL, NULL },
};

@@ -4898,7 +5090,7 @@ static PyObject *
Simple_repr(CDataObject *self)
{
PyObject *val, *result;
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));

if (Py_TYPE(self)->tp_base != st->Simple_Type) {
return PyUnicode_FromFormat("<%s object at %p>",
@@ -4953,7 +5145,7 @@ Pointer_item(PyObject *myself, Py_ssize_t index)
return NULL;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return NULL;
@@ -4997,7 +5189,7 @@ Pointer_ass_item(PyObject *myself, Py_ssize_t index, PyObject *value)
return -1;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return -1;
@@ -5030,7 +5222,7 @@ Pointer_get_contents(CDataObject *self, void *closure)
return NULL;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return NULL;
@@ -5053,7 +5245,7 @@ Pointer_set_contents(CDataObject *self, PyObject *value, void *closure)
"Pointer does not support item deletion");
return -1;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return -1;
@@ -5115,7 +5307,7 @@ Pointer_init(CDataObject *self, PyObject *args, PyObject *kw)
static PyObject *
Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
return NULL;
@@ -5195,7 +5387,7 @@ Pointer_subscript(PyObject *myself, PyObject *item)
else
len = (stop - start + 1) / step + 1;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(myself)));
StgInfo *stginfo;
if (PyStgInfo_FromObject(st, (PyObject *)self, &stginfo) < 0) {
return NULL;
@@ -5424,7 +5616,13 @@ cast_check_pointertype(ctypes_state *st, PyObject *arg)
static PyObject *
cast(void *ptr, PyObject *src, PyObject *ctype)
{
- ctypes_state *st = GLOBAL_STATE();
+ PyObject *mod = PyType_GetModuleByDef(Py_TYPE(ctype), &_ctypesmodule);
+ if (!mod) {
+ PyErr_SetString(PyExc_TypeError,
+ "cast() argument 2 must be a pointer type");
+ return NULL;
+ }
+ ctypes_state *st = get_module_state(mod);

CDataObject *result;
if (cast_check_pointertype(st, ctype) == 0) {
@@ -5493,15 +5691,6 @@ wstring_at(const wchar_t *ptr, int size)
}


-static struct PyModuleDef _ctypesmodule = {
- PyModuleDef_HEAD_INIT,
- .m_name = "_ctypes",
- .m_doc = _ctypes__doc__,
- .m_size = -1,
- .m_methods = _ctypes_module_methods,
-};
-
-
static int
_ctypes_add_types(PyObject *mod)
{
@@ -5525,7 +5714,7 @@ _ctypes_add_types(PyObject *mod)
} \
} while (0)

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(mod);

/* Note:
ob_type is the metatype (the 'type'), defaults to PyType_Type,
@@ -5610,7 +5799,7 @@ _ctypes_add_objects(PyObject *mod)
} \
} while (0)

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(mod);
MOD_ADD("_pointer_type_cache", Py_NewRef(st->_ctypes_ptrtype_cache));

#ifdef MS_WIN32
@@ -5653,7 +5842,7 @@ _ctypes_add_objects(PyObject *mod)
static int
_ctypes_mod_exec(PyObject *mod)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(mod);
st->_unpickle = PyObject_GetAttrString(mod, "_unpickle");
if (st->_unpickle == NULL) {
return -1;
@@ -5680,19 +5869,104 @@ _ctypes_mod_exec(PyObject *mod)
}


+static int
+module_traverse(PyObject *module, visitproc visit, void *arg) {
+ ctypes_state *st = get_module_state(module);
+ Py_VISIT(st->_ctypes_ptrtype_cache);
+ Py_VISIT(st->_unpickle);
+ Py_VISIT(st->array_cache);
+ Py_VISIT(st->error_object_name);
+ Py_VISIT(st->PyExc_ArgError);
+ Py_VISIT(st->swapped_suffix);
+
+ Py_VISIT(st->DictRemover_Type);
+ Py_VISIT(st->PyCArg_Type);
+ Py_VISIT(st->PyCField_Type);
+ Py_VISIT(st->PyCThunk_Type);
+ Py_VISIT(st->StructParam_Type);
+ Py_VISIT(st->PyCStructType_Type);
+ Py_VISIT(st->UnionType_Type);
+ Py_VISIT(st->PyCPointerType_Type);
+ Py_VISIT(st->PyCArrayType_Type);
+ Py_VISIT(st->PyCSimpleType_Type);
+ Py_VISIT(st->PyCFuncPtrType_Type);
+ Py_VISIT(st->PyCData_Type);
+ Py_VISIT(st->Struct_Type);
+ Py_VISIT(st->Union_Type);
+ Py_VISIT(st->PyCArray_Type);
+ Py_VISIT(st->Simple_Type);
+ Py_VISIT(st->PyCPointer_Type);
+ Py_VISIT(st->PyCFuncPtr_Type);
+#ifdef MS_WIN32
+ Py_VISIT(st->PyComError_Type);
+#endif
+ Py_VISIT(st->PyCType_Type);
+ return 0;
+}
+
+static int
+module_clear(PyObject *module) {
+ ctypes_state *st = get_module_state(module);
+ Py_CLEAR(st->_ctypes_ptrtype_cache);
+ Py_CLEAR(st->_unpickle);
+ Py_CLEAR(st->array_cache);
+ Py_CLEAR(st->error_object_name);
+ Py_CLEAR(st->PyExc_ArgError);
+ Py_CLEAR(st->swapped_suffix);
+
+ Py_CLEAR(st->DictRemover_Type);
+ Py_CLEAR(st->PyCArg_Type);
+ Py_CLEAR(st->PyCField_Type);
+ Py_CLEAR(st->PyCThunk_Type);
+ Py_CLEAR(st->StructParam_Type);
+ Py_CLEAR(st->PyCStructType_Type);
+ Py_CLEAR(st->UnionType_Type);
+ Py_CLEAR(st->PyCPointerType_Type);
+ Py_CLEAR(st->PyCArrayType_Type);
+ Py_CLEAR(st->PyCSimpleType_Type);
+ Py_CLEAR(st->PyCFuncPtrType_Type);
+ Py_CLEAR(st->PyCData_Type);
+ Py_CLEAR(st->Struct_Type);
+ Py_CLEAR(st->Union_Type);
+ Py_CLEAR(st->PyCArray_Type);
+ Py_CLEAR(st->Simple_Type);
+ Py_CLEAR(st->PyCPointer_Type);
+ Py_CLEAR(st->PyCFuncPtr_Type);
+#ifdef MS_WIN32
+ Py_CLEAR(st->PyComError_Type);
+#endif
+ Py_CLEAR(st->PyCType_Type);
+ return 0;
+}
+
+static void
+module_free(void *module)
+{
+ (void)module_clear((PyObject *)module);
+}
+
+static PyModuleDef_Slot module_slots[] = {
+ {Py_mod_exec, _ctypes_mod_exec},
+ {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
+ {0, NULL}
+};
+
+struct PyModuleDef _ctypesmodule = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "_ctypes",
+ .m_doc = _ctypes__doc__,
+ .m_size = sizeof(ctypes_state),
+ .m_methods = _ctypes_module_methods,
+ .m_slots = module_slots,
+ .m_traverse = module_traverse,
+ .m_clear = module_clear,
+ .m_free = module_free,
+};
+
PyMODINIT_FUNC
PyInit__ctypes(void)
{
- PyObject *mod = PyModule_Create(&_ctypesmodule);
- if (!mod) {
- return NULL;
- }
-
- if (_ctypes_mod_exec(mod) < 0) {
- Py_DECREF(mod);
- return NULL;
- }
- return mod;
+ return PyModuleDef_Init(&_ctypesmodule);
}

/*
diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c
index b6f98e92e1ba88..7b9f6437c7d55f 100644
--- a/Modules/_ctypes/callbacks.c
+++ b/Modules/_ctypes/callbacks.c
@@ -136,6 +136,8 @@ TryAddRef(PyObject *cnv, CDataObject *obj)
* Call the python object with all arguments
*
*/
+
+// BEWARE: The GIL needs to be held throughout the function
static void _CallPythonObject(ctypes_state *st,
void *mem,
ffi_type *restype,
@@ -149,7 +151,6 @@ static void _CallPythonObject(ctypes_state *st,
Py_ssize_t i = 0, j = 0, nargs = 0;
PyObject *error_object = NULL;
int *space;
- PyGILState_STATE state = PyGILState_Ensure();

assert(PyTuple_Check(converters));
nargs = PyTuple_GET_SIZE(converters);
@@ -294,7 +295,6 @@ static void _CallPythonObject(ctypes_state *st,
for (j = 0; j < i; j++) {
Py_DECREF(args[j]);
}
- PyGILState_Release(state);
}

static void closure_fcn(ffi_cif *cif,
@@ -302,8 +302,10 @@ static void closure_fcn(ffi_cif *cif,
void **args,
void *userdata)
{
+ PyGILState_STATE state = PyGILState_Ensure();
+
CThunkObject *p = (CThunkObject *)userdata;
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(Py_TYPE(p));

_CallPythonObject(st,
resp,
@@ -313,6 +315,8 @@ static void closure_fcn(ffi_cif *cif,
p->converters,
p->flags,
args);
+
+ PyGILState_Release(state);
}

static CThunkObject* CThunkObject_new(ctypes_state *st, Py_ssize_t nargs)
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index 67d6ade43a2667..cbed2f32caa6c4 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -201,7 +201,7 @@ static PyObject *
get_error_internal(PyObject *self, PyObject *args, int index)
{
int *space;
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
PyObject *errobj = _ctypes_get_errobj(st, &space);
PyObject *result;

@@ -222,7 +222,7 @@ set_error_internal(PyObject *self, PyObject *args, int index)
if (!PyArg_ParseTuple(args, "i", &new_errno)) {
return NULL;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
errobj = _ctypes_get_errobj(st, &space);
if (errobj == NULL)
return NULL;
@@ -1464,7 +1464,7 @@ copy_com_pointer(PyObject *self, PyObject *args)
return NULL;
a.keep = b.keep = NULL;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
if (ConvParam(st, p1, 0, &a) < 0 || ConvParam(st, p2, 1, &b) < 0) {
goto done;
}
@@ -1646,7 +1646,7 @@ call_function(PyObject *self, PyObject *args)
return NULL;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
result = _ctypes_callproc(st,
(PPROC)func,
arguments,
@@ -1683,7 +1683,7 @@ call_cdeclfunction(PyObject *self, PyObject *args)
return NULL;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
result = _ctypes_callproc(st,
(PPROC)func,
arguments,
@@ -1709,7 +1709,7 @@ PyDoc_STRVAR(sizeof_doc,
static PyObject *
sizeof_func(PyObject *self, PyObject *obj)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);

StgInfo *info;
if (PyStgInfo_FromType(st, obj, &info) < 0) {
@@ -1735,7 +1735,7 @@ PyDoc_STRVAR(alignment_doc,
static PyObject *
align_func(PyObject *self, PyObject *obj)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
StgInfo *info;
if (PyStgInfo_FromAny(st, obj, &info) < 0) {
return NULL;
@@ -1773,7 +1773,7 @@ byref(PyObject *self, PyObject *args)
if (offset == -1 && PyErr_Occurred())
return NULL;
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
if (!CDataObject_Check(st, obj)) {
PyErr_Format(PyExc_TypeError,
"byref() argument must be a ctypes instance, not '%s'",
@@ -1799,7 +1799,7 @@ PyDoc_STRVAR(addressof_doc,
static PyObject *
addressof(PyObject *self, PyObject *obj)
{
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
if (!CDataObject_Check(st, obj)) {
PyErr_SetString(PyExc_TypeError,
"invalid type");
@@ -1858,7 +1858,7 @@ resize(PyObject *self, PyObject *args)
&obj, &size))
return NULL;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
StgInfo *info;
int result = PyStgInfo_FromObject(st, (PyObject *)obj, &info);
if (result < 0) {
@@ -1956,7 +1956,8 @@ create_pointer_type(PyObject *module, PyObject *cls)
PyTypeObject *typ;
PyObject *key;

- ctypes_state *st = GLOBAL_STATE();
+ assert(module);
+ ctypes_state *st = get_module_state(module);
if (PyDict_GetItemRef(st->_ctypes_ptrtype_cache, cls, &result) != 0) {
// found or error
return result;
@@ -2019,12 +2020,12 @@ create_pointer_inst(PyObject *module, PyObject *arg)
PyObject *result;
PyObject *typ;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(module);
if (PyDict_GetItemRef(st->_ctypes_ptrtype_cache, (PyObject *)Py_TYPE(arg), &typ) < 0) {
return NULL;
}
if (typ == NULL) {
- typ = create_pointer_type(NULL, (PyObject *)Py_TYPE(arg));
+ typ = create_pointer_type(module, (PyObject *)Py_TYPE(arg));
if (typ == NULL)
return NULL;
}
@@ -2039,7 +2040,7 @@ buffer_info(PyObject *self, PyObject *arg)
PyObject *shape;
Py_ssize_t i;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state(self);
StgInfo *info;
if (PyStgInfo_FromAny(st, arg, &info) < 0) {
return NULL;
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index ffe00e25aff49f..7472a4c36868a8 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -216,7 +216,7 @@ PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value)
{
CDataObject *dst;
char *ptr;
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(Py_TYPE(self));
if (!CDataObject_Check(st, inst)) {
PyErr_SetString(PyExc_TypeError,
"not a ctype instance");
@@ -240,7 +240,7 @@ PyCField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type)
if (inst == NULL) {
return Py_NewRef(self);
}
- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(Py_TYPE(self));
if (!CDataObject_Check(st, inst)) {
PyErr_SetString(PyExc_TypeError,
"not a ctype instance");
diff --git a/Modules/_ctypes/clinic/_ctypes.c.h b/Modules/_ctypes/clinic/_ctypes.c.h
new file mode 100644
index 00000000000000..98a84cc14f4386
--- /dev/null
+++ b/Modules/_ctypes/clinic/_ctypes.c.h
@@ -0,0 +1,610 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#include "pycore_abstract.h" // _PyNumber_Index()
+#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
+
+PyDoc_STRVAR(_ctypes_CType_Type___sizeof____doc__,
+"__sizeof__($self, /)\n"
+"--\n"
+"\n"
+"Return memory consumption of the type object.");
+
+#define _CTYPES_CTYPE_TYPE___SIZEOF___METHODDEF \
+ {"__sizeof__", _PyCFunction_CAST(_ctypes_CType_Type___sizeof__), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _ctypes_CType_Type___sizeof____doc__},
+
+static PyObject *
+_ctypes_CType_Type___sizeof___impl(PyObject *self, PyTypeObject *cls);
+
+static PyObject *
+_ctypes_CType_Type___sizeof__(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
+ PyErr_SetString(PyExc_TypeError, "__sizeof__() takes no arguments");
+ return NULL;
+ }
+ return _ctypes_CType_Type___sizeof___impl(self, cls);
+}
+
+PyDoc_STRVAR(CDataType_from_address__doc__,
+"from_address($self, value, /)\n"
+"--\n"
+"\n"
+"C.from_address(integer) -> C instance\n"
+"\n"
+"Access a C instance at the specified address.");
+
+#define CDATATYPE_FROM_ADDRESS_METHODDEF \
+ {"from_address", _PyCFunction_CAST(CDataType_from_address), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, CDataType_from_address__doc__},
+
+static PyObject *
+CDataType_from_address_impl(PyObject *type, PyTypeObject *cls,
+ PyObject *value);
+
+static PyObject *
+CDataType_from_address(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_address",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ value = args[0];
+ return_value = CDataType_from_address_impl(type, cls, value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(CDataType_from_buffer__doc__,
+"from_buffer($self, obj, offset=0, /)\n"
+"--\n"
+"\n"
+"C.from_buffer(object, offset=0) -> C instance\n"
+"\n"
+"Create a C instance from a writeable buffer.");
+
+#define CDATATYPE_FROM_BUFFER_METHODDEF \
+ {"from_buffer", _PyCFunction_CAST(CDataType_from_buffer), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, CDataType_from_buffer__doc__},
+
+static PyObject *
+CDataType_from_buffer_impl(PyObject *type, PyTypeObject *cls, PyObject *obj,
+ Py_ssize_t offset);
+
+static PyObject *
+CDataType_from_buffer(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", "", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_buffer",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ PyObject *obj;
+ Py_ssize_t offset = 0;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ obj = args[0];
+ if (nargs < 2) {
+ goto skip_optional_posonly;
+ }
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[1]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ offset = ival;
+ }
+skip_optional_posonly:
+ return_value = CDataType_from_buffer_impl(type, cls, obj, offset);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(CDataType_from_buffer_copy__doc__,
+"from_buffer_copy($self, buffer, offset=0, /)\n"
+"--\n"
+"\n"
+"C.from_buffer_copy(object, offset=0) -> C instance\n"
+"\n"
+"Create a C instance from a readable buffer.");
+
+#define CDATATYPE_FROM_BUFFER_COPY_METHODDEF \
+ {"from_buffer_copy", _PyCFunction_CAST(CDataType_from_buffer_copy), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, CDataType_from_buffer_copy__doc__},
+
+static PyObject *
+CDataType_from_buffer_copy_impl(PyObject *type, PyTypeObject *cls,
+ Py_buffer *buffer, Py_ssize_t offset);
+
+static PyObject *
+CDataType_from_buffer_copy(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", "", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_buffer_copy",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ Py_buffer buffer = {NULL, NULL};
+ Py_ssize_t offset = 0;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ if (PyObject_GetBuffer(args[0], &buffer, PyBUF_SIMPLE) != 0) {
+ goto exit;
+ }
+ if (nargs < 2) {
+ goto skip_optional_posonly;
+ }
+ {
+ Py_ssize_t ival = -1;
+ PyObject *iobj = _PyNumber_Index(args[1]);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ offset = ival;
+ }
+skip_optional_posonly:
+ return_value = CDataType_from_buffer_copy_impl(type, cls, &buffer, offset);
+
+exit:
+ /* Cleanup for buffer */
+ if (buffer.obj) {
+ PyBuffer_Release(&buffer);
+ }
+
+ return return_value;
+}
+
+PyDoc_STRVAR(CDataType_in_dll__doc__,
+"in_dll($self, dll, name, /)\n"
+"--\n"
+"\n"
+"C.in_dll(dll, name) -> C instance\n"
+"\n"
+"Access a C instance in a dll.");
+
+#define CDATATYPE_IN_DLL_METHODDEF \
+ {"in_dll", _PyCFunction_CAST(CDataType_in_dll), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, CDataType_in_dll__doc__},
+
+static PyObject *
+CDataType_in_dll_impl(PyObject *type, PyTypeObject *cls, PyObject *dll,
+ const char *name);
+
+static PyObject *
+CDataType_in_dll(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", "", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "in_dll",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[2];
+ PyObject *dll;
+ const char *name;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ dll = args[0];
+ if (!PyUnicode_Check(args[1])) {
+ _PyArg_BadArgument("in_dll", "argument 2", "str", args[1]);
+ goto exit;
+ }
+ Py_ssize_t name_length;
+ name = PyUnicode_AsUTF8AndSize(args[1], &name_length);
+ if (name == NULL) {
+ goto exit;
+ }
+ if (strlen(name) != (size_t)name_length) {
+ PyErr_SetString(PyExc_ValueError, "embedded null character");
+ goto exit;
+ }
+ return_value = CDataType_in_dll_impl(type, cls, dll, name);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(CDataType_from_param__doc__,
+"from_param($self, value, /)\n"
+"--\n"
+"\n"
+"Convert a Python object into a function call parameter.");
+
+#define CDATATYPE_FROM_PARAM_METHODDEF \
+ {"from_param", _PyCFunction_CAST(CDataType_from_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, CDataType_from_param__doc__},
+
+static PyObject *
+CDataType_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value);
+
+static PyObject *
+CDataType_from_param(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_param",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ value = args[0];
+ return_value = CDataType_from_param_impl(type, cls, value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(PyCPointerType_set_type__doc__,
+"set_type($self, type, /)\n"
+"--\n"
+"\n");
+
+#define PYCPOINTERTYPE_SET_TYPE_METHODDEF \
+ {"set_type", _PyCFunction_CAST(PyCPointerType_set_type), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, PyCPointerType_set_type__doc__},
+
+static PyObject *
+PyCPointerType_set_type_impl(PyTypeObject *self, PyTypeObject *cls,
+ PyObject *type);
+
+static PyObject *
+PyCPointerType_set_type(PyTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "set_type",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *type;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ type = args[0];
+ return_value = PyCPointerType_set_type_impl(self, cls, type);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(PyCPointerType_from_param__doc__,
+"from_param($self, value, /)\n"
+"--\n"
+"\n"
+"Convert a Python object into a function call parameter.");
+
+#define PYCPOINTERTYPE_FROM_PARAM_METHODDEF \
+ {"from_param", _PyCFunction_CAST(PyCPointerType_from_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, PyCPointerType_from_param__doc__},
+
+static PyObject *
+PyCPointerType_from_param_impl(PyObject *type, PyTypeObject *cls,
+ PyObject *value);
+
+static PyObject *
+PyCPointerType_from_param(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_param",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ value = args[0];
+ return_value = PyCPointerType_from_param_impl(type, cls, value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(c_wchar_p_from_param__doc__,
+"from_param($self, value, /)\n"
+"--\n"
+"\n");
+
+#define C_WCHAR_P_FROM_PARAM_METHODDEF \
+ {"from_param", _PyCFunction_CAST(c_wchar_p_from_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, c_wchar_p_from_param__doc__},
+
+static PyObject *
+c_wchar_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value);
+
+static PyObject *
+c_wchar_p_from_param(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_param",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ value = args[0];
+ return_value = c_wchar_p_from_param_impl(type, cls, value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(c_char_p_from_param__doc__,
+"from_param($self, value, /)\n"
+"--\n"
+"\n");
+
+#define C_CHAR_P_FROM_PARAM_METHODDEF \
+ {"from_param", _PyCFunction_CAST(c_char_p_from_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, c_char_p_from_param__doc__},
+
+static PyObject *
+c_char_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value);
+
+static PyObject *
+c_char_p_from_param(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_param",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ value = args[0];
+ return_value = c_char_p_from_param_impl(type, cls, value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(c_void_p_from_param__doc__,
+"from_param($self, value, /)\n"
+"--\n"
+"\n");
+
+#define C_VOID_P_FROM_PARAM_METHODDEF \
+ {"from_param", _PyCFunction_CAST(c_void_p_from_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, c_void_p_from_param__doc__},
+
+static PyObject *
+c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value);
+
+static PyObject *
+c_void_p_from_param(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_param",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ value = args[0];
+ return_value = c_void_p_from_param_impl(type, cls, value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(PyCSimpleType_from_param__doc__,
+"from_param($self, value, /)\n"
+"--\n"
+"\n"
+"Convert a Python object into a function call parameter.");
+
+#define PYCSIMPLETYPE_FROM_PARAM_METHODDEF \
+ {"from_param", _PyCFunction_CAST(PyCSimpleType_from_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, PyCSimpleType_from_param__doc__},
+
+static PyObject *
+PyCSimpleType_from_param_impl(PyObject *type, PyTypeObject *cls,
+ PyObject *value);
+
+static PyObject *
+PyCSimpleType_from_param(PyObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+ # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
+ #else
+ # define KWTUPLE NULL
+ #endif
+
+ static const char * const _keywords[] = {"", NULL};
+ static _PyArg_Parser _parser = {
+ .keywords = _keywords,
+ .fname = "from_param",
+ .kwtuple = KWTUPLE,
+ };
+ #undef KWTUPLE
+ PyObject *argsbuf[1];
+ PyObject *value;
+
+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
+ if (!args) {
+ goto exit;
+ }
+ value = args[0];
+ return_value = PyCSimpleType_from_param_impl(type, cls, value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(PyCData_reduce__doc__,
+"__reduce__($self, /)\n"
+"--\n"
+"\n");
+
+#define PYCDATA_REDUCE_METHODDEF \
+ {"__reduce__", _PyCFunction_CAST(PyCData_reduce), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, PyCData_reduce__doc__},
+
+static PyObject *
+PyCData_reduce_impl(PyObject *myself, PyTypeObject *cls);
+
+static PyObject *
+PyCData_reduce(PyObject *myself, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
+ PyErr_SetString(PyExc_TypeError, "__reduce__() takes no arguments");
+ return NULL;
+ }
+ return PyCData_reduce_impl(myself, cls);
+}
+
+PyDoc_STRVAR(Simple_from_outparm__doc__,
+"__ctypes_from_outparam__($self, /)\n"
+"--\n"
+"\n");
+
+#define SIMPLE_FROM_OUTPARM_METHODDEF \
+ {"__ctypes_from_outparam__", _PyCFunction_CAST(Simple_from_outparm), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, Simple_from_outparm__doc__},
+
+static PyObject *
+Simple_from_outparm_impl(PyObject *self, PyTypeObject *cls);
+
+static PyObject *
+Simple_from_outparm(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
+ PyErr_SetString(PyExc_TypeError, "__ctypes_from_outparam__() takes no arguments");
+ return NULL;
+ }
+ return Simple_from_outparm_impl(self, cls);
+}
+/*[clinic end generated code: output=9c6539a3559e6088 input=a9049054013a1b77]*/
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 31b89dca244e8e..20c68134be2804 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -2,6 +2,9 @@
# include <alloca.h>
#endif

+#include "pycore_moduleobject.h" // _PyModule_GetState()
+#include "pycore_typeobject.h" // _PyType_GetModuleState()
+
#ifndef MS_WIN32
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
@@ -70,9 +73,48 @@ typedef struct {
PyObject *swapped_suffix;
} ctypes_state;

-extern ctypes_state global_state;

-#define GLOBAL_STATE() (&global_state)
+extern struct PyModuleDef _ctypesmodule;
+
+
+static inline ctypes_state *
+get_module_state(PyObject *module)
+{
+ void *state = _PyModule_GetState(module);
+ assert(state != NULL);
+ return (ctypes_state *)state;
+}
+
+static inline ctypes_state *
+get_module_state_by_class(PyTypeObject *cls)
+{
+ ctypes_state *state = (ctypes_state *)_PyType_GetModuleState(cls);
+ assert(state != NULL);
+ return state;
+}
+
+static inline ctypes_state *
+get_module_state_by_def(PyTypeObject *cls)
+{
+ PyObject *mod = PyType_GetModuleByDef(cls, &_ctypesmodule);
+ assert(mod != NULL);
+ return get_module_state(mod);
+}
+
+static inline ctypes_state *
+get_module_state_by_def_final(PyTypeObject *cls)
+{
+ if (cls->tp_mro == NULL) {
+ return NULL;
+ }
+ PyObject *mod = PyType_GetModuleByDef(cls, &_ctypesmodule);
+ if (mod == NULL) {
+ PyErr_Clear();
+ return NULL;
+ }
+ return get_module_state(mod);
+}
+

extern PyType_Spec carg_spec;
extern PyType_Spec cfield_spec;
diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c
index 7b09bae0dd2a57..ad82e4891c519a 100644
--- a/Modules/_ctypes/stgdict.c
+++ b/Modules/_ctypes/stgdict.c
@@ -94,7 +94,7 @@ MakeFields(PyObject *type, CFieldObject *descr,
if (fieldlist == NULL)
return -1;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_class(Py_TYPE(descr));
PyTypeObject *cfield_tp = st->PyCField_Type;
for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) {
PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */
@@ -175,7 +175,7 @@ MakeAnonFields(PyObject *type)
if (anon_names == NULL)
return -1;

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
PyTypeObject *cfield_tp = st->PyCField_Type;
for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) {
PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */
@@ -318,7 +318,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct
return -1;
}

- ctypes_state *st = GLOBAL_STATE();
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
StgInfo *stginfo;
if (PyStgInfo_FromType(st, type, &stginfo) < 0) {
return -1;
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index 965346b9b04a32..e0ae39036c128d 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -198,6 +198,7 @@ Python/pystate.c - _Py_tss_tstate -

Include/internal/pycore_blocks_output_buffer.h - BUFFER_BLOCK_SIZE -
Modules/_csv.c - quote_styles -
+Modules/_ctypes/_ctypes.c - _ctypesmodule -
Modules/_ctypes/cfield.c - ffi_type_double -
Modules/_ctypes/cfield.c - ffi_type_float -
Modules/_ctypes/cfield.c - ffi_type_longdouble -

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-leave@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: list-python-checkins@lists.gossamer-threads.com