diff -r 9927781e457f Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py Mon Dec 15 14:02:43 2014 +0200 +++ b/Lib/test/test_unicode.py Tue Dec 16 01:28:59 2014 +0200 @@ -1770,6 +1770,8 @@ class UnicodeTest( 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 9927781e457f Misc/NEWS --- a/Misc/NEWS Mon Dec 15 14:02:43 2014 +0200 +++ b/Misc/NEWS Tue Dec 16 01:28:59 2014 +0200 @@ -10,6 +10,9 @@ What's New in Python 2.7.10? Core and Builtins ----------------- +- Issue #23055: Fixed a buffer overflow in PyUnicode_FromFormatV. Analysis + and fix by Guido Vranken. + - Issue #23048: Fix jumping out of an infinite while loop in the pdb. Library diff -r 9927781e457f Objects/unicodeobject.c --- a/Objects/unicodeobject.c Mon Dec 15 14:02:43 2014 +0200 +++ b/Objects/unicodeobject.c Tue Dec 16 01:28:59 2014 +0200 @@ -735,15 +735,10 @@ PyUnicode_FromFormatV(const char *format * objects once during step 3 and put the result in an array) */ for (f = format; *f; f++) { if (*f == '%') { - if (*(f+1)=='%') - continue; - if (*(f+1)=='S' || *(f+1)=='R') - ++callcount; - while (isdigit((unsigned)*f)) - width = (width*10) + *f++ - '0'; - while (*++f && *f != '%' && !isalpha((unsigned)*f)) - ; - if (*f == 's') + f++; + while (*f && *f != '%' && !isalpha((unsigned)*f)) + f++; + if (*f == 's' || *f=='S' || *f=='R') ++callcount; } } @@ -760,12 +755,18 @@ PyUnicode_FromFormatV(const char *format /* 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; while (isdigit((unsigned)*f)) width = (width*10) + *f++ - '0'; - while (*++f && *f != '%' && !isalpha((unsigned)*f)) - ; + precision = 0; + 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,6 +806,8 @@ PyUnicode_FromFormatV(const char *format This isn't enough for octal. If a width is specified we need more (which we allocate later). */ + if (width < precision) + width = precision; if (width < 20) width = 20; n += width;