diff -r ebe8917189a3 Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py Mon Dec 15 10:04:13 2014 -0500 +++ b/Lib/test/test_unicode.py Mon Dec 15 09:14:00 2014 -0800 @@ -1770,6 +1770,8 @@ b'%+i', c_int(10)) check_format(u'%s', b'%.%s', b'abc') + check_format(u'0'*998 + u'42', + b'%01000d', c_int(42)) @test_support.cpython_only def test_encode_decimal(self): diff -r ebe8917189a3 Misc/NEWS --- a/Misc/NEWS Mon Dec 15 10:04:13 2014 -0500 +++ b/Misc/NEWS Mon Dec 15 09:14:00 2014 -0800 @@ -12,6 +12,9 @@ - Issue #23048: Fix jumping out of an infinite while loop in the pdb. +- Fixed a buffer overflow in PyUnicode_FromFormatV. Analysis and fix + by Guido Vranken. + Library ------- diff -r ebe8917189a3 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Mon Dec 15 10:04:13 2014 -0500 +++ b/Objects/unicodeobject.c Mon Dec 15 09:14:00 2014 -0800 @@ -760,12 +760,18 @@ /* step 3: figure out how large a buffer we need */ for (f = format; *f; f++) { if (*f == '%') { - const char* p = f; + const char* p = f++; width = 0; + precision = 0; while (isdigit((unsigned)*f)) width = (width*10) + *f++ - '0'; - while (*++f && *f != '%' && !isalpha((unsigned)*f)) - ; + if (*f == '.') { + f++; + while (isdigit((unsigned)*f)) + precision = (precision*10) + *f++ - '0'; + } + while (*f && *f != '%' && !isalpha((unsigned)*f)) + f++; /* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since * they don't affect the amount of space we reserve. @@ -805,11 +811,9 @@ This isn't enough for octal. If a width is specified we need more (which we allocate later). */ - if (width < 20) - width = 20; - n += width; - if (abuffersize < width) - abuffersize = width; + n += (width + precision) < 20 ? 20 : (width + precision); + if (abuffersize < (width + precision) ) + abuffersize = width + precision; break; case 's': {