diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2013-08-03 18:14:05 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2013-08-03 18:14:05 (GMT) |
commit | 579ddc2fd4fd618b72d8202d79d75d22e7e0b60a (patch) | |
tree | b6ac773514cfbef73d62130a0d3810626fbc38e7 /Objects | |
parent | e633bed44a6354dd190c7e97e28c12dead787315 (diff) | |
parent | f6d0aeeadce3f1aea240b900da5e1fbb430257b2 (diff) | |
download | cpython-579ddc2fd4fd618b72d8202d79d75d22e7e0b60a.zip cpython-579ddc2fd4fd618b72d8202d79d75d22e7e0b60a.tar.gz cpython-579ddc2fd4fd618b72d8202d79d75d22e7e0b60a.tar.bz2 |
Issue #16741: Fix an error reporting in int().
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 29 | ||||
-rw-r--r-- | Objects/longobject.c | 87 |
2 files changed, 64 insertions, 52 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index 6c8c561..5f11c3d 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1261,25 +1261,6 @@ convert_integral_to_int(PyObject *integral, const char *error_format) } -/* Add a check for embedded NULL-bytes in the argument. */ -static PyObject * -long_from_string(const char *s, Py_ssize_t len) -{ - char *end; - PyObject *x; - - x = PyLong_FromString((char*)s, &end, 10); - if (x == NULL) - return NULL; - if (end != s + len) { - PyErr_SetString(PyExc_ValueError, - "null byte in argument for int()"); - Py_DECREF(x); - return NULL; - } - return x; -} - PyObject * PyNumber_Long(PyObject *o) { @@ -1327,16 +1308,16 @@ PyNumber_Long(PyObject *o) if (PyBytes_Check(o)) /* need to do extra error checking that PyLong_FromString() - * doesn't do. In particular int('9.5') must raise an - * exception, not truncate the float. + * doesn't do. In particular int('9\x005') must raise an + * exception, not truncate at the null. */ - return long_from_string(PyBytes_AS_STRING(o), - PyBytes_GET_SIZE(o)); + return _PyLong_FromBytes(PyBytes_AS_STRING(o), + PyBytes_GET_SIZE(o), 10); if (PyUnicode_Check(o)) /* The above check is done in PyLong_FromUnicode(). */ return PyLong_FromUnicodeObject(o, 10); if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) - return long_from_string(buffer, buffer_len); + return _PyLong_FromBytes(buffer, buffer_len, 10); return type_error("int() argument must be a string or a " "number, not '%.200s'", o); diff --git a/Objects/longobject.c b/Objects/longobject.c index b47be40..e0d641a0 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2000,6 +2000,14 @@ long_from_binary_base(char **str, int base) return long_normalize(z); } +/* Parses a long from a bytestring. Leading and trailing whitespace will be + * ignored. + * + * If successful, a PyLong object will be returned and 'pend' will be pointing + * to the first unused byte unless it's NULL. + * + * If unsuccessful, NULL will be returned. + */ PyObject * PyLong_FromString(char *str, char **pend, int base) { @@ -2262,24 +2270,54 @@ digit beyond the first. str++; if (*str != '\0') goto onError; - if (pend) - *pend = str; long_normalize(z); - return (PyObject *) maybe_small_long(z); + z = maybe_small_long(z); + if (z == NULL) + return NULL; + if (pend != NULL) + *pend = str; + return (PyObject *) z; onError: + if (pend != NULL) + *pend = str; Py_XDECREF(z); slen = strlen(orig_str) < 200 ? strlen(orig_str) : 200; strobj = PyUnicode_FromStringAndSize(orig_str, slen); if (strobj == NULL) return NULL; PyErr_Format(PyExc_ValueError, - "invalid literal for int() with base %d: %R", + "invalid literal for int() with base %d: %.200R", base, strobj); Py_DECREF(strobj); return NULL; } +/* Since PyLong_FromString doesn't have a length parameter, + * check here for possible NULs in the string. + * + * Reports an invalid literal as a bytes object. + */ +PyObject * +_PyLong_FromBytes(const char *s, Py_ssize_t len, int base) +{ + PyObject *result, *strobj; + char *end = NULL; + + result = PyLong_FromString((char*)s, &end, base); + if (end == NULL || (result != NULL && end == s + len)) + return result; + Py_XDECREF(result); + strobj = PyBytes_FromStringAndSize(s, Py_MIN(len, 200)); + if (strobj != NULL) { + PyErr_Format(PyExc_ValueError, + "invalid literal for int() with base %d: %.200R", + base, strobj); + Py_DECREF(strobj); + } + return NULL; +} + PyObject * PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) { @@ -2294,9 +2332,8 @@ PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) PyObject * PyLong_FromUnicodeObject(PyObject *u, int base) { - PyObject *result; - PyObject *asciidig; - char *buffer, *end; + PyObject *result, *asciidig; + char *buffer, *end = NULL; Py_ssize_t buflen; asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u); @@ -2305,17 +2342,22 @@ PyLong_FromUnicodeObject(PyObject *u, int base) buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen); if (buffer == NULL) { Py_DECREF(asciidig); - return NULL; + if (!PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) + return NULL; } - result = PyLong_FromString(buffer, &end, base); - if (result != NULL && end != buffer + buflen) { - PyErr_SetString(PyExc_ValueError, - "null byte in argument for int()"); - Py_DECREF(result); - result = NULL; + else { + result = PyLong_FromString(buffer, &end, base); + if (end == NULL || (result != NULL && end == buffer + buflen)) { + Py_DECREF(asciidig); + return result; + } + Py_DECREF(asciidig); + Py_XDECREF(result); } - Py_DECREF(asciidig); - return result; + PyErr_Format(PyExc_ValueError, + "invalid literal for int() with base %d: %.200R", + base, u); + return NULL; } /* forward */ @@ -4319,23 +4361,12 @@ long_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (PyUnicode_Check(x)) return PyLong_FromUnicodeObject(x, (int)base); else if (PyByteArray_Check(x) || PyBytes_Check(x)) { - /* Since PyLong_FromString doesn't have a length parameter, - * check here for possible NULs in the string. */ char *string; - Py_ssize_t size = Py_SIZE(x); if (PyByteArray_Check(x)) string = PyByteArray_AS_STRING(x); else string = PyBytes_AS_STRING(x); - if (strlen(string) != (size_t)size || !size) { - /* We only see this if there's a null byte in x or x is empty, - x is a bytes or buffer, *and* a base is given. */ - PyErr_Format(PyExc_ValueError, - "invalid literal for int() with base %d: %R", - (int)base, x); - return NULL; - } - return PyLong_FromString(string, NULL, (int)base); + return _PyLong_FromBytes(string, Py_SIZE(x), (int)base); } else { PyErr_SetString(PyExc_TypeError, |