]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-148675: Use a string for ctypes cparam tag (GH-149778) (#149869)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 15 May 2026 11:52:55 +0000 (13:52 +0200)
committerGitHub <noreply@github.com>
Fri, 15 May 2026 11:52:55 +0000 (11:52 +0000)
gh-148675: Use a string for ctypes cparam tag (GH-149778)
(cherry picked from commit 3ecca22567249ae44bf4369fbdb4d6d056701405)

Co-authored-by: Victor Stinner <vstinner@python.org>
Lib/test/test_ctypes/test_parameters.py
Modules/_ctypes/_ctypes.c
Modules/_ctypes/callproc.c
Modules/_ctypes/ctypes.h

index 46f8ff93efa9152f89bd35c27853ecd58d7e0eba..6dadb7b410d7034ce25fd136c40d9e7cdee0677a 100644 (file)
@@ -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 @@ class SimpleTypesTestCase(unittest.TestCase):
         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):
index 98ac821c525a647033522f80d25598a17f323390..09eae97dd21a36654c8795a9f0d565afb4ef9b11 100644 (file)
@@ -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;
index e208e27c5dbed42a43fcf7561811b9b5c73b90ea..e453cfeec9cc8ca01aa94a6d36f30149b014fa32 100644 (file)
@@ -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;
index 7b6b7f08582251b4713a45dc9f330b8306354e7f..248559aa364a1986d373162e3ad33cae325c35f7 100644 (file)
@@ -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))