at 22.05-pre 7.1 kB view raw
1From fab838b2ee7cfb9037c24f0f18dfe01aa379b3f7 Mon Sep 17 00:00:00 2001 2From: Benjamin Peterson <benjamin@python.org> 3Date: Mon, 18 Jan 2021 15:11:46 -0600 4Subject: [3.6] closes bpo-42938: Replace snprintf with Python unicode 5 formatting in ctypes param reprs. (GH-24250) 6MIME-Version: 1.0 7Content-Type: text/plain; charset=UTF-8 8Content-Transfer-Encoding: 8bit 9 10(cherry picked from commit 916610ef90a0d0761f08747f7b0905541f0977c7) 11 12Co-authored-by: Benjamin Peterson <benjamin@python.org> 13Rebased for Python 2.7 by Michał Górny <mgorny@gentoo.org> 14--- 15 Lib/ctypes/test/test_parameters.py | 43 +++++++++++++++++++ 16 .../2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst | 2 + 17 Modules/_ctypes/callproc.c | 49 +++++++++++----------- 18 3 files changed, 69 insertions(+), 25 deletions(-) 19 create mode 100644 Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst 20 21diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py 22index 23c1b6e225..3456882ccb 100644 23--- a/Lib/ctypes/test/test_parameters.py 24+++ b/Lib/ctypes/test/test_parameters.py 25@@ -206,6 +206,49 @@ class SimpleTypesTestCase(unittest.TestCase): 26 with self.assertRaises(ZeroDivisionError): 27 WorseStruct().__setstate__({}, b'foo') 28 29+ def test_parameter_repr(self): 30+ from ctypes import ( 31+ c_bool, 32+ c_char, 33+ c_wchar, 34+ c_byte, 35+ c_ubyte, 36+ c_short, 37+ c_ushort, 38+ c_int, 39+ c_uint, 40+ c_long, 41+ c_ulong, 42+ c_longlong, 43+ c_ulonglong, 44+ c_float, 45+ c_double, 46+ c_longdouble, 47+ c_char_p, 48+ c_wchar_p, 49+ c_void_p, 50+ ) 51+ self.assertRegexpMatches(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$") 52+ self.assertEqual(repr(c_char.from_param('a')), "<cparam 'c' (a)>") 53+ self.assertRegexpMatches(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$") 54+ self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>") 55+ self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>") 56+ self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>") 57+ self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>") 58+ self.assertRegexpMatches(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$") 59+ self.assertRegexpMatches(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$") 60+ self.assertRegexpMatches(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$") 61+ self.assertRegexpMatches(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$") 62+ self.assertRegexpMatches(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$") 63+ self.assertRegexpMatches(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$") 64+ self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>") 65+ self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>") 66+ self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>") 67+ self.assertRegexpMatches(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$") 68+ self.assertRegexpMatches(repr(c_char_p.from_param(b'hihi')), "^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$") 69+ self.assertRegexpMatches(repr(c_wchar_p.from_param('hihi')), "^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$") 70+ self.assertRegexpMatches(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$") 71+ 72 ################################################################ 73 74 if __name__ == '__main__': 75diff --git a/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst b/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst 76new file mode 100644 77index 0000000000..7df65a156f 78--- /dev/null 79+++ b/Misc/NEWS.d/next/Security/2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst 80@@ -0,0 +1,2 @@ 81+Avoid static buffers when computing the repr of :class:`ctypes.c_double` and 82+:class:`ctypes.c_longdouble` values. 83diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c 84index 066fefc0cc..421addf353 100644 85--- a/Modules/_ctypes/callproc.c 86+++ b/Modules/_ctypes/callproc.c 87@@ -460,50 +460,51 @@ PyCArg_dealloc(PyCArgObject *self) 88 static PyObject * 89 PyCArg_repr(PyCArgObject *self) 90 { 91- char buffer[256]; 92 switch(self->tag) { 93 case 'b': 94 case 'B': 95- sprintf(buffer, "<cparam '%c' (%d)>", 96+ return PyString_FromFormat("<cparam '%c' (%d)>", 97 self->tag, self->value.b); 98- break; 99 case 'h': 100 case 'H': 101- sprintf(buffer, "<cparam '%c' (%d)>", 102+ return PyString_FromFormat("<cparam '%c' (%d)>", 103 self->tag, self->value.h); 104- break; 105 case 'i': 106 case 'I': 107- sprintf(buffer, "<cparam '%c' (%d)>", 108+ return PyString_FromFormat("<cparam '%c' (%d)>", 109 self->tag, self->value.i); 110- break; 111 case 'l': 112 case 'L': 113- sprintf(buffer, "<cparam '%c' (%ld)>", 114+ return PyString_FromFormat("<cparam '%c' (%ld)>", 115 self->tag, self->value.l); 116- break; 117 118 #ifdef HAVE_LONG_LONG 119 case 'q': 120 case 'Q': 121- sprintf(buffer, 122+ return PyString_FromFormat( 123 "<cparam '%c' (%" PY_FORMAT_LONG_LONG "d)>", 124 self->tag, self->value.q); 125- break; 126 #endif 127 case 'd': 128- sprintf(buffer, "<cparam '%c' (%f)>", 129- self->tag, self->value.d); 130- break; 131- case 'f': 132- sprintf(buffer, "<cparam '%c' (%f)>", 133- self->tag, self->value.f); 134- break; 135- 136+ case 'f': { 137+ PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d); 138+ if (f == NULL) { 139+ return NULL; 140+ } 141+ PyObject *r = PyObject_Repr(f); 142+ if (r == NULL) { 143+ Py_DECREF(f); 144+ return NULL; 145+ } 146+ PyObject *result = PyString_FromFormat( 147+ "<cparam '%c' (%s)>", self->tag, PyString_AsString(r)); 148+ Py_DECREF(r); 149+ Py_DECREF(f); 150+ return result; 151+ } 152 case 'c': 153- sprintf(buffer, "<cparam '%c' (%c)>", 154+ return PyString_FromFormat("<cparam '%c' (%c)>", 155 self->tag, self->value.c); 156- break; 157 158 /* Hm, are these 'z' and 'Z' codes useful at all? 159 Shouldn't they be replaced by the functionality of c_string 160@@ -512,16 +513,14 @@ PyCArg_repr(PyCArgObject *self) 161 case 'z': 162 case 'Z': 163 case 'P': 164- sprintf(buffer, "<cparam '%c' (%p)>", 165+ return PyString_FromFormat("<cparam '%c' (%p)>", 166 self->tag, self->value.p); 167 break; 168 169 default: 170- sprintf(buffer, "<cparam '%c' at %p>", 171+ return PyString_FromFormat("<cparam '%c' at %p>", 172 self->tag, self); 173- break; 174 } 175- return PyString_FromString(buffer); 176 } 177 178 static PyMemberDef PyCArgType_members[] = { 179-- 180cgit v1.2.3 181