cpython: 4fd48a807812 (original) (raw)
Mercurial > cpython
changeset 84996:4fd48a807812
Issue #16741: Fix an error reporting in int(). [#16741]
Serhiy Storchaka storchaka@gmail.com | |
---|---|
date | Sat, 03 Aug 2013 21:14:05 +0300 |
parents | ab1859ba1a78(current diff)ecc8512b427d(diff) |
children | 673ef3f96919 |
files | Include/longobject.h Lib/test/test_int.py Misc/NEWS Objects/abstract.c Objects/longobject.c |
diffstat | 5 files changed, 100 insertions(+), 70 deletions(-)[+] [-] Include/longobject.h 1 Lib/test/test_int.py 47 Misc/NEWS 2 Objects/abstract.c 29 Objects/longobject.c 91 |
line wrap: on
line diff
--- a/Include/longobject.h +++ b/Include/longobject.h @@ -97,6 +97,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromString #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject ) PyLong_FromUnicode(Py_UNICODE, Py_ssize_t, int); PyAPI_FUNC(PyObject *) PyLong_FromUnicodeObject(PyObject *u, int base); +PyAPI_FUNC(PyObject *) _PyLong_FromBytes(const char *, Py_ssize_t, int); #endif #ifndef Py_LIMITED_API
--- a/Lib/test/test_int.py +++ b/Lib/test/test_int.py @@ -73,14 +73,6 @@ class IntTestCases(unittest.TestCase): x = -1-sys.maxsize self.assertEqual(x >> 1, x//2)
self.assertRaises(ValueError, int, '123\0')[](#l2.7)
self.assertRaises(ValueError, int, '53', 40)[](#l2.8)
# SF bug 1545497: embedded NULs were not detected with[](#l2.10)
# explicit base[](#l2.11)
self.assertRaises(ValueError, int, '123\0', 10)[](#l2.12)
self.assertRaises(ValueError, int, '123\x00 245', 20)[](#l2.13)
- x = int('1' * 600) self.assertIsInstance(x, int) @@ -401,14 +393,37 @@ class IntTestCases(unittest.TestCase): int(TruncReturnsBadInt()) def test_error_message(self):
testlist = ('\xbd', '123\xbd', ' 123 456 ')[](#l2.22)
for s in testlist:[](#l2.23)
try:[](#l2.24)
int(s)[](#l2.25)
except ValueError as e:[](#l2.26)
self.assertIn(s.strip(), e.args[0])[](#l2.27)
else:[](#l2.28)
self.fail("Expected int(%r) to raise a ValueError", s)[](#l2.29)
def check(s, base=None):[](#l2.30)
with self.assertRaises(ValueError,[](#l2.31)
msg="int(%r, %r)" % (s, base)) as cm:[](#l2.32)
if base is None:[](#l2.33)
int(s)[](#l2.34)
else:[](#l2.35)
int(s, base)[](#l2.36)
self.assertEqual(cm.exception.args[0],[](#l2.37)
"invalid literal for int() with base %d: %r" %[](#l2.38)
(10 if base is None else base, s))[](#l2.39)
check('\xbd')[](#l2.41)
check('123\xbd')[](#l2.42)
check(' 123 456 ')[](#l2.43)
check('123\x00')[](#l2.45)
# SF bug 1545497: embedded NULs were not detected with explicit base[](#l2.46)
check('123\x00', 10)[](#l2.47)
check('123\x00 245', 20)[](#l2.48)
check('123\x00 245', 16)[](#l2.49)
check('123\x00245', 20)[](#l2.50)
check('123\x00245', 16)[](#l2.51)
# byte string with embedded NUL[](#l2.52)
check(b'123\x00')[](#l2.53)
check(b'123\x00', 10)[](#l2.54)
# non-UTF-8 byte string[](#l2.55)
check(b'123\xbd')[](#l2.56)
check(b'123\xbd', 10)[](#l2.57)
# lone surrogate in Unicode string[](#l2.58)
check('123\ud800')[](#l2.59)
check('123\ud800', 10)[](#l2.60)
def test_main(): support.run_unittest(IntTestCases)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ What's New in Python 3.4.0 Alpha 1? Core and Builtins ----------------- +- Issue #16741: Fix an error reporting in int(). +
- Issue #17899: Fix rare file descriptor leak in os.listdir().
- Issue #9035: ismount now recognises volumes mounted below a drive root
--- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1261,25 +1261,6 @@ convert_integral_to_int(PyObject integr } -/ Add a check for embedded NULL-bytes in the argument. */ -static PyObject * -long_from_string(const char *s, Py_ssize_t len) -{
- x = PyLong_FromString((char*)s, &end, 10);
- if (x == NULL)
return NULL;[](#l4.16)
- if (end != s + len) {
PyErr_SetString(PyExc_ValueError,[](#l4.18)
"null byte in argument for int()");[](#l4.19)
Py_DECREF(x);[](#l4.20)
return NULL;[](#l4.21)
- }
- 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[](#l4.33)
* exception, not truncate the float.[](#l4.34)
* doesn't do. In particular int('9\x005') must raise an[](#l4.35)
* exception, not truncate at the null.[](#l4.36) */[](#l4.37)
return long_from_string(PyBytes_AS_STRING(o),[](#l4.38)
PyBytes_GET_SIZE(o));[](#l4.39)
return _PyLong_FromBytes(PyBytes_AS_STRING(o),[](#l4.40)
if (PyUnicode_Check(o)) /* The above check is done in PyLong_FromUnicode(). */ return PyLong_FromUnicodeObject(o, 10); if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))PyBytes_GET_SIZE(o), 10);[](#l4.41)
return long_from_string(buffer, buffer_len);[](#l4.46)
return _PyLong_FromBytes(buffer, buffer_len, 10);[](#l4.47)
return type_error("int() argument must be a string or a " "number, not '%.200s'", o);
--- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2000,6 +2000,14 @@ long_from_binary_base(char *str, int ba return long_normalize(z); } +/ Parses a long from a bytestring. Leading and trailing whitespace will be
- *
- *
- */ PyObject * PyLong_FromString(char *str, char **pend, int base) { @@ -2262,24 +2270,54 @@ digit beyond the first. str++; if (*str != '\0') goto onError;
- long_normalize(z);
- z = maybe_small_long(z);
- if (z == NULL)
return NULL;[](#l5.26)
- if (pend != NULL) *pend = str;
- if (pend != NULL)
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,*pend = str;[](#l5.35)
"invalid literal for int() with base %d: %R",[](#l5.42)
Py_DECREF(strobj); return NULL; } +/* Since PyLong_FromString doesn't have a length parameter,"invalid literal for int() with base %d: %.200R",[](#l5.43) base, strobj);[](#l5.44)
- *
- */ +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;[](#l5.62)
- Py_XDECREF(result);
- strobj = PyBytes_FromStringAndSize(s, Py_MIN(len, 200));
- if (strobj != NULL) {
PyErr_Format(PyExc_ValueError,[](#l5.66)
"invalid literal for int() with base %d: %.200R",[](#l5.67)
base, strobj);[](#l5.68)
Py_DECREF(strobj);[](#l5.69)
- }
- return NULL;
+} + PyObject * PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) { @@ -2294,9 +2332,8 @@ PyLong_FromUnicode(Py_UNICODE *u, Py_ssi PyObject * PyLong_FromUnicodeObject(PyObject *u, int base) {
- PyObject *result, *asciidig;
- char *buffer, *end = NULL; Py_ssize_t buflen; asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u); @@ -2305,17 +2342,22 @@ PyLong_FromUnicodeObject(PyObject *u, in buffer = PyUnicode_AsUTF8AndSize(asciidig, &buflen); if (buffer == NULL) { Py_DECREF(asciidig);
return NULL;[](#l5.93)
- }
- result = PyLong_FromString(buffer, &end, base);
- if (result != NULL && end != buffer + buflen) {
PyErr_SetString(PyExc_ValueError,[](#l5.97)
"null byte in argument for int()");[](#l5.98)
Py_DECREF(result);[](#l5.99)
result = NULL;[](#l5.100)
- }
- Py_DECREF(asciidig);
- return result;
if (!PyErr_ExceptionMatches(PyExc_UnicodeEncodeError))[](#l5.104)
return NULL;[](#l5.105)
- }
- else {
result = PyLong_FromString(buffer, &end, base);[](#l5.108)
if (end == NULL || (result != NULL && end == buffer + buflen)) {[](#l5.109)
Py_DECREF(asciidig);[](#l5.110)
return result;[](#l5.111)
}[](#l5.112)
Py_DECREF(asciidig);[](#l5.113)
Py_XDECREF(result);[](#l5.114)
- }
- PyErr_Format(PyExc_ValueError,
"invalid literal for int() with base %d: %.200R",[](#l5.117)
base, u);[](#l5.118)
- return NULL;
} /* forward */ @@ -4319,23 +4361,12 @@ long_new(PyTypeObject *type, PyObject *a 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,[](#l5.127)
* check here for possible NULs in the string. */[](#l5.128) char *string;[](#l5.129)
Py_ssize_t size = Py_SIZE(x);[](#l5.130) if (PyByteArray_Check(x))[](#l5.131) string = PyByteArray_AS_STRING(x);[](#l5.132) else[](#l5.133) string = PyBytes_AS_STRING(x);[](#l5.134)
if (strlen(string) != (size_t)size || !size) {[](#l5.135)
/* We only see this if there's a null byte in x or x is empty,[](#l5.136)
x is a bytes or buffer, *and* a base is given. */[](#l5.137)
PyErr_Format(PyExc_ValueError,[](#l5.138)
"invalid literal for int() with base %d: %R",[](#l5.139)
(int)base, x);[](#l5.140)
return NULL;[](#l5.141)
}[](#l5.142)
return PyLong_FromString(string, NULL, (int)base);[](#l5.143)