Index: Objects/unicodeobject.c =================================================================== --- Objects/unicodeobject.c (revision 85697) +++ Objects/unicodeobject.c (working copy) @@ -9214,6 +9214,13 @@ return -1; } + +/* Constants for the type of % argument being used -- not known, + a mapping, or a tuple. */ +#define FORMAT_TYPE_UNKNOWN 0 +#define FORMAT_TYPE_MAPPING 1 +#define FORMAT_TYPE_TUPLE 2 + /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) FORMATBUFLEN is the length of the buffer in which chars are formatted. */ @@ -9225,6 +9232,7 @@ Py_UNICODE *fmt, *res; Py_ssize_t fmtcnt, rescnt, reslen, arglen, argidx; int args_owned = 0; + int format_type = FORMAT_TYPE_UNKNOWN; PyUnicodeObject *result = NULL; PyObject *dict = NULL; PyObject *uformat; @@ -9290,7 +9298,13 @@ Py_ssize_t keylen; PyObject *key; int pcount = 1; - + if (format_type == FORMAT_TYPE_TUPLE) { + PyErr_SetString(PyExc_ValueError, + "both keyed and unkeyed format " + "specifiers used"); + goto onError; + } + format_type = FORMAT_TYPE_MAPPING; if (dict == NULL) { PyErr_SetString(PyExc_TypeError, "format requires a mapping"); @@ -9339,6 +9353,18 @@ arglen = -1; argidx = -2; } + /* Check if it's really format specifier and set format_type*/ + else if (*fmt != '%') { + if (format_type == FORMAT_TYPE_MAPPING) { + PyErr_SetString(PyExc_ValueError, + "both keyed and unkeyed format " + "specifiers used"); + goto onError; + } + else if (format_type == FORMAT_TYPE_UNKNOWN) { + format_type = FORMAT_TYPE_TUPLE; + } + } while (--fmtcnt >= 0) { switch (c = *fmt++) { case '-': flags |= F_LJUST; continue;