Index: Objects/stringobject.c =================================================================== --- Objects/stringobject.c (revision 50819) +++ Objects/stringobject.c (working copy) @@ -4437,6 +4437,12 @@ */ #define FORMATBUFLEN (size_t)120 +/* 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 + PyObject * PyString_Format(PyObject *format, PyObject *args) { @@ -4444,6 +4450,7 @@ Py_ssize_t arglen, argidx; Py_ssize_t reslen, rescnt, fmtcnt; int args_owned = 0; + int format_type = FORMAT_TYPE_UNKNOWN; PyObject *result, *orig_args; #ifdef Py_USING_UNICODE PyObject *v, *w; @@ -4516,6 +4523,12 @@ "format requires a mapping"); goto error; } + if (format_type == FORMAT_TYPE_TUPLE) { + PyErr_SetString(PyExc_ValueError, + "both keyed and unkeyed format specifiers used"); + goto error; + } + format_type = FORMAT_TYPE_MAPPING; ++fmt; --fmtcnt; keystart = fmt; @@ -4550,6 +4563,14 @@ arglen = -1; argidx = -2; } + else if (format_type == FORMAT_TYPE_MAPPING) { + PyErr_SetString(PyExc_ValueError, + "both keyed and unkeyed format specifiers used"); + goto error; + } + else if (format_type == FORMAT_TYPE_UNKNOWN) { + format_type = FORMAT_TYPE_TUPLE; + } while (--fmtcnt >= 0) { switch (c = *fmt++) { case '-': flags |= F_LJUST; continue;