diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 42df721eb0e..2c416a3c47c 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -1716,9 +1716,10 @@ class UnicodeTest(string_tests.CommonTest, # Test PyUnicode_FromFormat() def test_from_format(self): support.import_module('ctypes') - from ctypes import (pythonapi, py_object, + from ctypes import ( + pythonapi, py_object, sizeof, c_int, c_long, c_longlong, c_ssize_t, - c_uint, c_ulong, c_ulonglong, c_size_t) + c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p) name = "PyUnicode_FromFormat" _PyUnicode_FromFormat = getattr(pythonapi, name) _PyUnicode_FromFormat.restype = py_object @@ -1769,6 +1770,15 @@ class UnicodeTest(string_tests.CommonTest, self.assertEqual(PyUnicode_FromFormat(b'%llu', c_ulonglong(123)), '123') self.assertEqual(PyUnicode_FromFormat(b'%zu', c_size_t(123)), '123') + # test long output + min_longlong = -(2 ** (8 * sizeof(c_longlong) - 1)) + max_longlong = -min_longlong - 1 + self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(min_longlong)), str(min_longlong)) + self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(max_longlong)), str(max_longlong)) + max_ulonglong = 2 ** (8 * sizeof(c_ulonglong)) - 1 + self.assertEqual(PyUnicode_FromFormat(b'%llu', c_ulonglong(max_ulonglong)), str(max_ulonglong)) + PyUnicode_FromFormat(b'%p', c_void_p(-1)) + # test padding (width and/or precision) self.assertEqual(PyUnicode_FromFormat(b'%010i', c_int(123)), '123'.rjust(10, '0')) self.assertEqual(PyUnicode_FromFormat(b'%100i', c_int(123)), '123'.rjust(100)) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index e6fe1fba4e2..0ed38fef8f5 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2328,10 +2328,7 @@ makefmt(char *fmt, int longflag, int longlongflag, int size_tflag, *fmt = '\0'; } -/* maximum number of characters required for output of %ld. 21 characters - allows for 64-bit integers (in decimal) and an optional sign. */ -#define MAX_LONG_CHARS 21 -/* maximum number of characters required for output of %lld. +/* maximum number of characters required for output of %lld or %p. We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, plus 1 for the sign. 53/22 is an upper bound for log10(256). */ #define MAX_LONG_LONG_CHARS (2 + (SIZEOF_LONG_LONG*53-1) / 22) @@ -2436,19 +2433,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, { /* used by sprintf */ char fmt[10]; /* should be enough for "%0lld\0" */ - char small_buffer[MAX_LONG_CHARS]; - char *buffer; - int err; - - if (sizeof(small_buffer) - 1 < precision) { - buffer = PyMem_Malloc(precision + 1); - if (buffer == NULL) { - PyErr_NoMemory(); - return NULL; - } - } - else - buffer = small_buffer; + char buffer[MAX_LONG_LONG_CHARS]; if (*f == 'u') { makefmt(fmt, longflag, longlongflag, size_tflag, *f); @@ -2492,45 +2477,28 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, } assert(len >= 0); - err = 0; if (precision < len) precision = len; if (width > precision) { Py_UCS4 fillchar; fill = width - precision; fillchar = zeropad?'0':' '; - if (_PyUnicodeWriter_Prepare(writer, fill, fillchar) != -1) { - if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1) - err = 1; - } - else - err = 1; - if (!err) - writer->pos += fill; + if (_PyUnicodeWriter_Prepare(writer, fill, fillchar) == -1) + return NULL; + if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1) + return NULL; + writer->pos += fill; } - if (!err && precision > len) { + if (precision > len) { fill = precision - len; - if (_PyUnicodeWriter_Prepare(writer, fill, '0') != -1) { - if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1) - err = 1; - } - else - err = 1; - if (!err) - writer->pos += fill; + if (_PyUnicodeWriter_Prepare(writer, fill, '0') == -1) + return NULL; + if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1) + return NULL; + writer->pos += fill; } - if (!err) { - if (_PyUnicodeWriter_WriteCstr(writer, buffer, len) == -1) - err = 1; - } - - if (buffer != small_buffer) { - PyMem_Free(buffer); - buffer = small_buffer; - } - if (err) + if (_PyUnicodeWriter_WriteCstr(writer, buffer, len) == -1) return NULL; - break; }