diff -r ed0c30b4c082 Lib/test/test_int.py --- a/Lib/test/test_int.py Sat May 04 15:16:16 2013 +0300 +++ b/Lib/test/test_int.py Sun May 05 22:22:38 2013 +0300 @@ -73,14 +73,6 @@ x = -1-sys.maxsize self.assertEqual(x >> 1, x//2) - self.assertRaises(ValueError, int, '123\0') - self.assertRaises(ValueError, int, '53', 40) - - # SF bug 1545497: embedded NULs were not detected with - # explicit base - self.assertRaises(ValueError, int, '123\0', 10) - self.assertRaises(ValueError, int, '123\x00 245', 20) - x = int('1' * 600) self.assertIsInstance(x, int) @@ -401,14 +393,34 @@ int(TruncReturnsBadInt()) def test_error_message(self): - testlist = ('\xbd', '123\xbd', ' 123 456 ') - for s in testlist: - try: - int(s) - except ValueError as e: - self.assertIn(s.strip(), e.args[0]) - else: - self.fail("Expected int(%r) to raise a ValueError", s) + def check(s, base=None): + with self.assertRaises(ValueError, + msg="int(%r, %r)" % (s, base)) as cm: + if base is None: + int(s) + else: + int(s, base) + self.assertEqual(cm.exception.args[0], + "invalid literal for int() with base %d: %r" % + (10 if base is None else base, s)) + + check('\xbd') + check('123\xbd') + check(' 123 456 ') + + check('123\0') + # SF bug 1545497: embedded NULs were not detected with + # explicit base + check('123\0', 10) + check('123\x00 245', 20) + check('123\x00 245', 16) + check(b'123\0') + check(b'123\0', 10) + check(b'123\xbd') + check(b'123\xbd', 10) + + check('123\ud800') + check('123\ud800', 10) def test_main(): support.run_unittest(IntTestCases) diff -r ed0c30b4c082 Objects/abstract.c --- a/Objects/abstract.c Sat May 04 15:16:16 2013 +0300 +++ b/Objects/abstract.c Sun May 05 22:22:38 2013 +0300 @@ -1265,19 +1265,21 @@ static PyObject * long_from_string(const char *s, Py_ssize_t len) { - char *end; - PyObject *x; + char *end = NULL; + PyObject *x, *strobj; 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; + if (end == NULL || (x != NULL && end == s + len)) + return x; + Py_XDECREF(x); + strobj = PyBytes_FromStringAndSize(s, Py_MIN(len, 200)); + if (strobj != NULL) { + PyErr_Format(PyExc_ValueError, + "invalid literal for int() with base %d: %R", + 10, strobj); + Py_DECREF(strobj); } - return x; + return NULL; } PyObject * @@ -1327,8 +1329,8 @@ 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)); diff -r ed0c30b4c082 Objects/longobject.c --- a/Objects/longobject.c Sat May 04 15:16:16 2013 +0300 +++ b/Objects/longobject.c Sun May 05 22:22:38 2013 +0300 @@ -1994,6 +1994,14 @@ 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) { @@ -2256,12 +2264,17 @@ str++; if (*str != '\0') goto onError; - if (pend) + long_normalize(z); + z = maybe_small_long(z); + if (z == NULL) + return NULL; + if (pend != NULL) *pend = str; - long_normalize(z); - return (PyObject *) maybe_small_long(z); + 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); @@ -2290,8 +2303,9 @@ { PyObject *result; PyObject *asciidig; - char *buffer, *end; + char *buffer, *end = NULL; Py_ssize_t buflen; + PyObject *strobj; asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u); if (asciidig == NULL) @@ -2299,17 +2313,24 @@ buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen); if (buffer == NULL) { Py_DECREF(asciidig); - 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; - } - Py_DECREF(asciidig); - return result; + if (!PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) + return NULL; + } + else { + result = PyLong_FromString(buffer, &end, base); + Py_DECREF(asciidig); + if (end == NULL || (result != NULL && end == buffer + buflen)) + return result; + Py_XDECREF(result); + } + strobj = PySequence_GetSlice(u, 0, 200); + if (strobj != NULL) { + PyErr_Format(PyExc_ValueError, + "invalid literal for int() with base %d: %R", + base, strobj); + Py_DECREF(strobj); + } + return NULL; } /* forward */