diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2015-01-27 20:18:34 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2015-01-27 20:18:34 (GMT) |
commit | 3f95292be69ac09ed173e4241d220d30b1b059ff (patch) | |
tree | cb02282df238300dcc32084e57e49cf4d8fab87a /Objects | |
parent | f18bf6fd2d2f0d7db6a5e5b4d86b709dd2b5ce6d (diff) | |
download | cpython-3f95292be69ac09ed173e4241d220d30b1b059ff.zip cpython-3f95292be69ac09ed173e4241d220d30b1b059ff.tar.gz cpython-3f95292be69ac09ed173e4241d220d30b1b059ff.tar.bz2 |
Issue #23055: Fixed a buffer overflow in PyUnicode_FromFormatV. Analysis
and fix by Guido Vranken.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/unicodeobject.c | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index b798850..1d1d531 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -759,15 +759,10 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) * result in an array) */ for (f = format; *f; f++) { if (*f == '%') { - if (*(f+1)=='%') - continue; - if (*(f+1)=='S' || *(f+1)=='R' || *(f+1)=='A' || *(f+1) == 'V') - ++callcount; - while (Py_ISDIGIT((unsigned)*f)) - width = (width*10) + *f++ - '0'; - while (*++f && *f != '%' && !Py_ISALPHA((unsigned)*f)) - ; - if (*f == 's') + f++; + while (*f && *f != '%' && !Py_ISALPHA((unsigned)*f)) + f++; + if (*f == 's' || *f=='S' || *f=='R' || *f=='A' || *f=='V') ++callcount; } else if (128 <= (unsigned char)*f) { @@ -794,12 +789,16 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) #ifdef HAVE_LONG_LONG int longlongflag = 0; #endif - const char* p = f; + const char* p = f++; width = 0; while (Py_ISDIGIT((unsigned)*f)) width = (width*10) + *f++ - '0'; - while (*++f && *f != '%' && !Py_ISALPHA((unsigned)*f)) - ; + precision = 0; + if (*f == '.') { + f++; + while (Py_ISDIGIT((unsigned)*f)) + precision = (precision*10) + *f++ - '0'; + } /* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since * they don't affect the amount of space we reserve. @@ -823,16 +822,18 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) switch (*f) { case 'c': { -#ifndef Py_UNICODE_WIDE int ordinal = va_arg(count, int); + if (ordinal < 0 || ordinal > 0x10ffff) { + PyErr_SetString(PyExc_OverflowError, + "%c arg not in range(0x110000)"); + goto fail; + } +#ifndef Py_UNICODE_WIDE if (ordinal > 0xffff) n += 2; else - n++; -#else - (void)va_arg(count, int); - n++; #endif + n++; break; } case '%': @@ -840,6 +841,8 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) break; case 'd': case 'u': case 'i': case 'x': (void) va_arg(count, int); + if (width < precision) + width = precision; #ifdef HAVE_LONG_LONG if (longlongflag) { if (width < MAX_LONG_LONG_CHARS) |