diff options
Diffstat (limited to 'Objects/stringlib/string_format.h')
| -rw-r--r-- | Objects/stringlib/string_format.h | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/Objects/stringlib/string_format.h b/Objects/stringlib/string_format.h index b2095fd..c46bdc2 100644 --- a/Objects/stringlib/string_format.h +++ b/Objects/stringlib/string_format.h @@ -197,7 +197,6 @@ get_integer(const SubString *str) { Py_ssize_t accumulator = 0; Py_ssize_t digitval; - Py_ssize_t oldaccumulator; STRINGLIB_CHAR *p; /* empty string is an error */ @@ -209,19 +208,17 @@ get_integer(const SubString *str) if (digitval < 0) return -1; /* - This trick was copied from old Unicode format code. It's cute, - but would really suck on an old machine with a slow divide - implementation. Fortunately, in the normal case we do not - expect too many digits. + Detect possible overflow before it happens: + + accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if + accumulator > (PY_SSIZE_T_MAX - digitval) / 10. */ - oldaccumulator = accumulator; - accumulator *= 10; - if ((accumulator+10)/10 != oldaccumulator+1) { + if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) { PyErr_Format(PyExc_ValueError, "Too many decimal digits in format string"); return -1; } - accumulator += digitval; + accumulator = accumulator * 10 + digitval; } return accumulator; } @@ -499,15 +496,28 @@ get_field_object(SubString *input, PyObject *args, PyObject *kwargs, PyObject *key = SubString_new_object(&first); if (key == NULL) goto error; - if ((kwargs == NULL) || (obj = PyDict_GetItem(kwargs, key)) == NULL) { + + /* Use PyObject_GetItem instead of PyDict_GetItem because this + code is no longer just used with kwargs. It might be passed + a non-dict when called through format_map. */ + if ((kwargs == NULL) || (obj = PyObject_GetItem(kwargs, key)) == NULL) { PyErr_SetObject(PyExc_KeyError, key); Py_DECREF(key); goto error; } Py_DECREF(key); - Py_INCREF(obj); } else { + /* If args is NULL, we have a format string with a positional field + with only kwargs to retrieve it from. This can only happen when + used with format_map(), where positional arguments are not + allowed. */ + if (args == NULL) { + PyErr_SetString(PyExc_ValueError, "Format string contains " + "positional fields"); + goto error; + } + /* look up in args */ obj = PySequence_GetItem(args, index); if (obj == NULL) @@ -1039,6 +1049,11 @@ do_string_format(PyObject *self, PyObject *args, PyObject *kwargs) return build_string(&input, args, kwargs, recursion_depth, &auto_number); } +static PyObject * +do_string_format_map(PyObject *self, PyObject *obj) +{ + return do_string_format(self, NULL, obj); +} /************************************************************************/ @@ -1180,10 +1195,15 @@ static PyTypeObject PyFormatterIter_Type = { describing the parsed elements. It's a wrapper around stringlib/string_format.h's MarkupIterator */ static PyObject * -formatter_parser(STRINGLIB_OBJECT *self) +formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) { formatteriterobject *it; + if (!PyUnicode_Check(self)) { + PyErr_Format(PyExc_TypeError, "expected str, got %s", Py_TYPE(self)->tp_name); + return NULL; + } + it = PyObject_New(formatteriterobject, &PyFormatterIter_Type); if (it == NULL) return NULL; @@ -1315,7 +1335,7 @@ static PyTypeObject PyFieldNameIter_Type = { field_name_split. The iterator it returns is a FieldNameIterator */ static PyObject * -formatter_field_name_split(STRINGLIB_OBJECT *self) +formatter_field_name_split(PyObject *ignored, STRINGLIB_OBJECT *self) { SubString first; Py_ssize_t first_idx; @@ -1324,6 +1344,11 @@ formatter_field_name_split(STRINGLIB_OBJECT *self) PyObject *first_obj = NULL; PyObject *result = NULL; + if (!PyUnicode_Check(self)) { + PyErr_Format(PyExc_TypeError, "expected str, got %s", Py_TYPE(self)->tp_name); + return NULL; + } + it = PyObject_New(fieldnameiterobject, &PyFieldNameIter_Type); if (it == NULL) return NULL; |
