Skip to content

Commit 916610e

Browse files
authored
closes bpo-42938: Replace snprintf with Python unicode formatting in ctypes param reprs. (24239)
1 parent 6a809fa commit 916610e

File tree

3 files changed

+64
-32
lines changed

3 files changed

+64
-32
lines changed

Lib/ctypes/test/test_parameters.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,49 @@ def __dict__(self):
201201
with self.assertRaises(ZeroDivisionError):
202202
WorseStruct().__setstate__({}, b'foo')
203203

204+
def test_parameter_repr(self):
205+
from ctypes import (
206+
c_bool,
207+
c_char,
208+
c_wchar,
209+
c_byte,
210+
c_ubyte,
211+
c_short,
212+
c_ushort,
213+
c_int,
214+
c_uint,
215+
c_long,
216+
c_ulong,
217+
c_longlong,
218+
c_ulonglong,
219+
c_float,
220+
c_double,
221+
c_longdouble,
222+
c_char_p,
223+
c_wchar_p,
224+
c_void_p,
225+
)
226+
self.assertRegex(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$")
227+
self.assertEqual(repr(c_char.from_param(97)), "<cparam 'c' ('a')>")
228+
self.assertRegex(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$")
229+
self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>")
230+
self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>")
231+
self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>")
232+
self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>")
233+
self.assertRegex(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
234+
self.assertRegex(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
235+
self.assertRegex(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
236+
self.assertRegex(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
237+
self.assertRegex(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$")
238+
self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$")
239+
self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>")
240+
self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>")
241+
self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>")
242+
self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$")
243+
self.assertRegex(repr(c_char_p.from_param(b'hihi')), "^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$")
244+
self.assertRegex(repr(c_wchar_p.from_param('hihi')), "^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$")
245+
self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$")
246+
204247
################################################################
205248

206249
if __name__ == '__main__':
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid static buffers when computing the repr of :class:`ctypes.c_double` and
2+
:class:`ctypes.c_longdouble` values.

Modules/_ctypes/callproc.c

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -487,58 +487,47 @@ is_literal_char(unsigned char c)
487487
static PyObject *
488488
PyCArg_repr(PyCArgObject *self)
489489
{
490-
char buffer[256];
491490
switch(self->tag) {
492491
case 'b':
493492
case 'B':
494-
sprintf(buffer, "<cparam '%c' (%d)>",
493+
return PyUnicode_FromFormat("<cparam '%c' (%d)>",
495494
self->tag, self->value.b);
496-
break;
497495
case 'h':
498496
case 'H':
499-
sprintf(buffer, "<cparam '%c' (%d)>",
497+
return PyUnicode_FromFormat("<cparam '%c' (%d)>",
500498
self->tag, self->value.h);
501-
break;
502499
case 'i':
503500
case 'I':
504-
sprintf(buffer, "<cparam '%c' (%d)>",
501+
return PyUnicode_FromFormat("<cparam '%c' (%d)>",
505502
self->tag, self->value.i);
506-
break;
507503
case 'l':
508504
case 'L':
509-
sprintf(buffer, "<cparam '%c' (%ld)>",
505+
return PyUnicode_FromFormat("<cparam '%c' (%ld)>",
510506
self->tag, self->value.l);
511-
break;
512507

513508
case 'q':
514509
case 'Q':
515-
sprintf(buffer,
516-
#ifdef MS_WIN32
517-
"<cparam '%c' (%I64d)>",
518-
#else
519-
"<cparam '%c' (%lld)>",
520-
#endif
510+
return PyUnicode_FromFormat("<cparam '%c' (%lld)>",
521511
self->tag, self->value.q);
522-
break;
523512
case 'd':
524-
sprintf(buffer, "<cparam '%c' (%f)>",
525-
self->tag, self->value.d);
526-
break;
527-
case 'f':
528-
sprintf(buffer, "<cparam '%c' (%f)>",
529-
self->tag, self->value.f);
530-
break;
531-
513+
case 'f': {
514+
PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d);
515+
if (f == NULL) {
516+
return NULL;
517+
}
518+
PyObject *result = PyUnicode_FromFormat("<cparam '%c' (%R)>", self->tag, f);
519+
Py_DECREF(f);
520+
return result;
521+
}
532522
case 'c':
533523
if (is_literal_char((unsigned char)self->value.c)) {
534-
sprintf(buffer, "<cparam '%c' ('%c')>",
524+
return PyUnicode_FromFormat("<cparam '%c' ('%c')>",
535525
self->tag, self->value.c);
536526
}
537527
else {
538-
sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
528+
return PyUnicode_FromFormat("<cparam '%c' ('\\x%02x')>",
539529
self->tag, (unsigned char)self->value.c);
540530
}
541-
break;
542531

543532
/* Hm, are these 'z' and 'Z' codes useful at all?
544533
Shouldn't they be replaced by the functionality of c_string
@@ -547,22 +536,20 @@ PyCArg_repr(PyCArgObject *self)
547536
case 'z':
548537
case 'Z':
549538
case 'P':
550-
sprintf(buffer, "<cparam '%c' (%p)>",
539+
return PyUnicode_FromFormat("<cparam '%c' (%p)>",
551540
self->tag, self->value.p);
552541
break;
553542

554543
default:
555544
if (is_literal_char((unsigned char)self->tag)) {
556-
sprintf(buffer, "<cparam '%c' at %p>",
545+
return PyUnicode_FromFormat("<cparam '%c' at %p>",
557546
(unsigned char)self->tag, (void *)self);
558547
}
559548
else {
560-
sprintf(buffer, "<cparam 0x%02x at %p>",
549+
return PyUnicode_FromFormat("<cparam 0x%02x at %p>",
561550
(unsigned char)self->tag, (void *)self);
562551
}
563-
break;
564552
}
565-
return PyUnicode_FromString(buffer);
566553
}
567554

568555
static PyMemberDef PyCArgType_members[] = {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy