https://github.com/python/cpython/commit/3ecca22567249ae44bf4369fbdb4d6d056701405
commit: 3ecca22567249ae44bf4369fbdb4d6d056701405
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-05-15T13:25:09+02:00
summary:
gh-148675: Use a string for ctypes cparam tag (#149778)
files:
M Lib/test/test_ctypes/test_parameters.py
M Modules/_ctypes/_ctypes.c
M Modules/_ctypes/callproc.c
M Modules/_ctypes/ctypes.h
diff --git a/Lib/test/test_ctypes/test_parameters.py
b/Lib/test/test_ctypes/test_parameters.py
index 46f8ff93efa915..6dadb7b410d703 100644
--- a/Lib/test/test_ctypes/test_parameters.py
+++ b/Lib/test/test_ctypes/test_parameters.py
@@ -1,6 +1,7 @@
import sys
import unittest
import test.support
+import ctypes
from ctypes import (CDLL, PyDLL, ArgumentError,
Structure, Array, Union,
_Pointer, _SimpleCData, _CFuncPtr,
@@ -247,6 +248,13 @@ def test_parameter_repr(self):
self.assertRegex(repr(c_char_p.from_param(b'hihi')), r"^<cparam 'z'
\(0x[A-Fa-f0-9]+\)>$")
self.assertRegex(repr(c_wchar_p.from_param('hihi')), r"^<cparam 'Z'
\(0x[A-Fa-f0-9]+\)>$")
self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P'
\(0x0*12\)>$")
+ if hasattr(ctypes, 'c_double_complex'):
+ self.assertRegex(repr(ctypes.c_double_complex.from_param(0)),
+ r"^<cparam 'Zd' at 0x[A-Fa-f0-9]+>$")
+ self.assertRegex(repr(ctypes.c_float_complex.from_param(0)),
+ r"^<cparam 'Zf' at 0x[A-Fa-f0-9]+>$")
+ self.assertRegex(repr(ctypes.c_longdouble_complex.from_param(0)),
+ r"^<cparam 'Zg' at 0x[A-Fa-f0-9]+>$")
@test.support.cpython_only
def test_from_param_result_refcount(self):
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 98ac821c525a64..09eae97dd21a36 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -708,7 +708,7 @@ StructUnionType_paramfunc(ctypes_state *st, CDataObject
*self)
}
assert(stginfo); /* Cannot be NULL for structure/union instances */
- parg->tag = 'V';
+ parg->tag = "V";
parg->pffi_type = &stginfo->ffi_type_pointer;
parg->value.p = ptr;
parg->size = self->b_size;
@@ -1282,7 +1282,7 @@ PyCPointerType_paramfunc(ctypes_state *st, CDataObject
*self)
if (parg == NULL)
return NULL;
- parg->tag = 'P';
+ parg->tag = "P";
parg->pffi_type = &ffi_type_pointer;
parg->obj = Py_NewRef(self);
parg->value.p = *(void **)self->b_ptr;
@@ -1703,7 +1703,7 @@ PyCArrayType_paramfunc(ctypes_state *st, CDataObject
*self)
PyCArgObject *p = PyCArgObject_new(st);
if (p == NULL)
return NULL;
- p->tag = 'P';
+ p->tag = "P";
p->pffi_type = &ffi_type_pointer;
p->value.p = (char *)self->b_ptr;
p->obj = Py_NewRef(self);
@@ -1909,7 +1909,7 @@ c_wchar_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (parg == NULL)
return NULL;
parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'Z';
+ parg->tag = "Z";
parg->obj = fd->setfunc(&parg->value, value, 0);
if (parg->obj == NULL) {
Py_DECREF(parg);
@@ -1998,7 +1998,7 @@ c_char_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (parg == NULL)
return NULL;
parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'z';
+ parg->tag = "z";
parg->obj = fd->setfunc(&parg->value, value, 0);
if (parg->obj == NULL) {
Py_DECREF(parg);
@@ -2092,7 +2092,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (parg == NULL)
return NULL;
parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'P';
+ parg->tag = "P";
parg->obj = fd->setfunc(&parg->value, value, sizeof(void*));
if (parg->obj == NULL) {
Py_DECREF(parg);
@@ -2110,7 +2110,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (parg == NULL)
return NULL;
parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'z';
+ parg->tag = "z";
parg->obj = fd->setfunc(&parg->value, value, 0);
if (parg->obj == NULL) {
Py_DECREF(parg);
@@ -2127,7 +2127,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (parg == NULL)
return NULL;
parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'Z';
+ parg->tag = "Z";
parg->obj = fd->setfunc(&parg->value, value, 0);
if (parg->obj == NULL) {
Py_DECREF(parg);
@@ -2152,7 +2152,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (PyCArg_CheckExact(st, value)) {
/* byref(c_xxx()) */
PyCArgObject *a = (PyCArgObject *)value;
- if (a->tag == 'P') {
+ if (strcmp(a->tag, "P") == 0) {
return Py_NewRef(value);
}
}
@@ -2165,7 +2165,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (parg == NULL)
return NULL;
parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'P';
+ parg->tag = "P";
Py_INCREF(value);
// Function pointers don't change their contents, no need to lock
parg->value.p = *(void **)func->b_ptr;
@@ -2191,7 +2191,7 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject
*cls, PyObject *value)
if (parg == NULL)
return NULL;
parg->pffi_type = &ffi_type_pointer;
- parg->tag = 'Z';
+ parg->tag = "Z";
parg->obj = Py_NewRef(value);
/* Remember: b_ptr points to where the pointer is stored! */
Py_BEGIN_CRITICAL_SECTION(value);
@@ -2332,7 +2332,8 @@ PyCSimpleType_paramfunc(ctypes_state *st, CDataObject
*self)
if (parg == NULL)
return NULL;
- parg->tag = fmt[0];
+ assert(strcmp(fd->code, fmt) == 0);
+ parg->tag = fd->code;
parg->pffi_type = fd->pffi_type;
parg->obj = Py_NewRef(self);
memcpy(&parg->value, self->b_ptr, self->b_size);
@@ -2578,7 +2579,8 @@ PyCSimpleType_from_param_impl(PyObject *type,
PyTypeObject *cls,
if (parg == NULL)
return NULL;
- parg->tag = fmt[0];
+ assert(strcmp(fd->code, fmt) == 0);
+ parg->tag = fd->code;
parg->pffi_type = fd->pffi_type;
parg->obj = fd->setfunc(&parg->value, value, info->size);
if (parg->obj)
@@ -2832,7 +2834,7 @@ PyCFuncPtrType_paramfunc(ctypes_state *st, CDataObject
*self)
if (parg == NULL)
return NULL;
- parg->tag = 'P';
+ parg->tag = "P";
parg->pffi_type = &ffi_type_pointer;
parg->obj = Py_NewRef(self);
parg->value.p = *(void **)self->b_ptr;
@@ -4303,7 +4305,7 @@ _byref(ctypes_state *st, PyObject *obj)
return NULL;
}
- parg->tag = 'P';
+ parg->tag = "P";
parg->pffi_type = &ffi_type_pointer;
parg->obj = obj;
parg->value.p = ((CDataObject *)obj)->b_ptr;
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index e208e27c5dbed4..e453cfeec9cc8c 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -468,7 +468,7 @@ PyCArgObject_new(ctypes_state *st)
if (p == NULL)
return NULL;
p->pffi_type = NULL;
- p->tag = '\0';
+ p->tag = "";
p->obj = NULL;
memset(&p->value, 0, sizeof(p->value));
PyObject_GC_Track(p);
@@ -512,45 +512,50 @@ static PyObject *
PyCArg_repr(PyObject *op)
{
PyCArgObject *self = _PyCArgObject_CAST(op);
- switch(self->tag) {
+
+ if (strlen(self->tag) != 1) {
+ goto generic;
+ }
+
+ switch(self->tag[0]) {
case 'b':
case 'B':
- return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+ return PyUnicode_FromFormat("<cparam '%s' (%d)>",
self->tag, self->value.b);
case 'h':
case 'H':
- return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+ return PyUnicode_FromFormat("<cparam '%s' (%d)>",
self->tag, self->value.h);
case 'i':
case 'I':
- return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+ return PyUnicode_FromFormat("<cparam '%s' (%d)>",
self->tag, self->value.i);
case 'l':
case 'L':
- return PyUnicode_FromFormat("<cparam '%c' (%ld)>",
+ return PyUnicode_FromFormat("<cparam '%s' (%ld)>",
self->tag, self->value.l);
case 'q':
case 'Q':
- return PyUnicode_FromFormat("<cparam '%c' (%lld)>",
+ return PyUnicode_FromFormat("<cparam '%s' (%lld)>",
self->tag, self->value.q);
case 'd':
case 'f': {
- PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f :
self->value.d);
+ PyObject *f = PyFloat_FromDouble((strcmp(self->tag, "f") == 0) ?
self->value.f : self->value.d);
if (f == NULL) {
return NULL;
}
- PyObject *result = PyUnicode_FromFormat("<cparam '%c' (%R)>",
self->tag, f);
+ PyObject *result = PyUnicode_FromFormat("<cparam '%s' (%R)>",
self->tag, f);
Py_DECREF(f);
return result;
}
case 'c':
if (is_literal_char((unsigned char)self->value.c)) {
- return PyUnicode_FromFormat("<cparam '%c' ('%c')>",
+ return PyUnicode_FromFormat("<cparam '%s' ('%c')>",
self->tag, self->value.c);
}
else {
- return PyUnicode_FromFormat("<cparam '%c' ('\\x%02x')>",
+ return PyUnicode_FromFormat("<cparam '%s' ('\\x%02x')>",
self->tag, (unsigned char)self->value.c);
}
@@ -561,20 +566,16 @@ PyCArg_repr(PyObject *op)
case 'z':
case 'Z':
case 'P':
- return PyUnicode_FromFormat("<cparam '%c' (%p)>",
+ return PyUnicode_FromFormat("<cparam '%s' (%p)>",
self->tag, self->value.p);
- break;
default:
- if (is_literal_char((unsigned char)self->tag)) {
- return PyUnicode_FromFormat("<cparam '%c' at %p>",
- (unsigned char)self->tag, (void *)self);
- }
- else {
- return PyUnicode_FromFormat("<cparam 0x%02x at %p>",
- (unsigned char)self->tag, (void *)self);
- }
+ break;
}
+
+generic:
+ return PyUnicode_FromFormat("<cparam '%s' at %p>",
+ self->tag, (void *)self);
}
static PyMemberDef PyCArgType_members[] = {
@@ -1807,7 +1808,7 @@ _ctypes_byref_impl(PyObject *module, PyObject *obj,
Py_ssize_t offset)
if (parg == NULL)
return NULL;
- parg->tag = 'P';
+ parg->tag = "P";
parg->pffi_type = &ffi_type_pointer;
parg->obj = Py_NewRef(obj);
parg->value.p = (char *)((CDataObject *)obj)->b_ptr + offset;
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 7b6b7f08582251..248559aa364a19 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -494,7 +494,7 @@ PyObject *_ctypes_callproc(ctypes_state *st,
struct tagPyCArgObject {
PyObject_HEAD
ffi_type *pffi_type;
- char tag;
+ const char *tag;
union {
char c;
char b;
@@ -511,7 +511,7 @@ struct tagPyCArgObject {
long double G[2];
} value;
PyObject *obj;
- Py_ssize_t size; /* for the 'V' tag */
+ Py_ssize_t size; /* for the "V" tag */
};
#define _PyCArgObject_CAST(op) ((PyCArgObject *)(op))
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]