Skip to content

Commit 34df10a

Browse files
authored
[3.6] closes bpo-42938: Replace snprintf with Python unicode formatting in ctypes param reprs. (GH-24250)
(cherry picked from commit 916610e) Co-authored-by: Benjamin Peterson <benjamin@python.org>
1 parent 415c4a1 commit 34df10a

File tree

3 files changed

+66
-34
lines changed

3 files changed

+66
-34
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: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -461,58 +461,47 @@ is_literal_char(unsigned char c)
461461
static PyObject *
462462
PyCArg_repr(PyCArgObject *self)
463463
{
464-
char buffer[256];
465464
switch(self->tag) {
466465
case 'b':
467466
case 'B':
468-
sprintf(buffer, "<cparam '%c' (%d)>",
467+
return PyUnicode_FromFormat("<cparam '%c' (%d)>",
469468
self->tag, self->value.b);
470-
break;
471469
case 'h':
472470
case 'H':
473-
sprintf(buffer, "<cparam '%c' (%d)>",
471+
return PyUnicode_FromFormat("<cparam '%c' (%d)>",
474472
self->tag, self->value.h);
475-
break;
476473
case 'i':
477474
case 'I':
478-
sprintf(buffer, "<cparam '%c' (%d)>",
475+
return PyUnicode_FromFormat("<cparam '%c' (%d)>",
479476
self->tag, self->value.i);
480-
break;
481477
case 'l':
482478
case 'L':
483-
sprintf(buffer, "<cparam '%c' (%ld)>",
479+
return PyUnicode_FromFormat("<cparam '%c' (%ld)>",
484480
self->tag, self->value.l);
485-
break;
486481

487482
case 'q':
488483
case 'Q':
489-
sprintf(buffer,
490-
#ifdef MS_WIN32
491-
"<cparam '%c' (%I64d)>",
492-
#else
493-
"<cparam '%c' (%lld)>",
494-
#endif
484+
return PyUnicode_FromFormat("<cparam '%c' (%lld)>",
495485
self->tag, self->value.q);
496-
break;
497486
case 'd':
498-
sprintf(buffer, "<cparam '%c' (%f)>",
499-
self->tag, self->value.d);
500-
break;
501-
case 'f':
502-
sprintf(buffer, "<cparam '%c' (%f)>",
503-
self->tag, self->value.f);
504-
break;
505-
487+
case 'f': {
488+
PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d);
489+
if (f == NULL) {
490+
return NULL;
491+
}
492+
PyObject *result = PyUnicode_FromFormat("<cparam '%c' (%R)>", self->tag, f);
493+
Py_DECREF(f);
494+
return result;
495+
}
506496
case 'c':
507497
if (is_literal_char((unsigned char)self->value.c)) {
508-
sprintf(buffer, "<cparam '%c' ('%c')>",
498+
return PyUnicode_FromFormat("<cparam '%c' ('%c')>",
509499
self->tag, self->value.c);
510500
}
511501
else {
512-
sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
502+
return PyUnicode_FromFormat("<cparam '%c' ('\\x%02x')>",
513503
self->tag, (unsigned char)self->value.c);
514504
}
515-
break;
516505

517506
/* Hm, are these 'z' and 'Z' codes useful at all?
518507
Shouldn't they be replaced by the functionality of c_string
@@ -521,22 +510,20 @@ PyCArg_repr(PyCArgObject *self)
521510
case 'z':
522511
case 'Z':
523512
case 'P':
524-
sprintf(buffer, "<cparam '%c' (%p)>",
513+
return PyUnicode_FromFormat("<cparam '%c' (%p)>",
525514
self->tag, self->value.p);
526515
break;
527516

528517
default:
529518
if (is_literal_char((unsigned char)self->tag)) {
530-
sprintf(buffer, "<cparam '%c' at %p>",
531-
(unsigned char)self->tag, self);
519+
return PyUnicode_FromFormat("<cparam '%c' at %p>",
520+
(unsigned char)self->tag, (void *)self);
532521
}
533522
else {
534-
sprintf(buffer, "<cparam 0x%02x at %p>",
535-
(unsigned char)self->tag, self);
523+
return PyUnicode_FromFormat("<cparam 0x%02x at %p>",
524+
(unsigned char)self->tag, (void *)self);
536525
}
537-
break;
538526
}
539-
return PyUnicode_FromString(buffer);
540527
}
541528

542529
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