diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index 8a194aa03d..65f6ede3af 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -140,10 +140,12 @@ class Unsigned_TestCase(unittest.TestCase): self.assertEqual(1, getargs_b(BadInt2())) self.assertEqual(0, getargs_b(BadInt3())) + self.assertRaises(OverflowError, getargs_b, -1 << 1000) self.assertRaises(OverflowError, getargs_b, -1) self.assertEqual(0, getargs_b(0)) self.assertEqual(UCHAR_MAX, getargs_b(UCHAR_MAX)) self.assertRaises(OverflowError, getargs_b, UCHAR_MAX + 1) + self.assertRaises(OverflowError, getargs_b, 1 << 1000) self.assertEqual(42, getargs_b(42)) self.assertRaises(OverflowError, getargs_b, VERY_LARGE) @@ -239,10 +241,12 @@ class Signed_TestCase(unittest.TestCase): self.assertEqual(1, getargs_h(BadInt2())) self.assertEqual(0, getargs_h(BadInt3())) + self.assertRaises(OverflowError, getargs_h, -1 << 1000) self.assertRaises(OverflowError, getargs_h, SHRT_MIN-1) self.assertEqual(SHRT_MIN, getargs_h(SHRT_MIN)) self.assertEqual(SHRT_MAX, getargs_h(SHRT_MAX)) self.assertRaises(OverflowError, getargs_h, SHRT_MAX+1) + self.assertRaises(OverflowError, getargs_h, 1 << 1000) self.assertEqual(42, getargs_h(42)) self.assertRaises(OverflowError, getargs_h, VERY_LARGE) @@ -258,10 +262,12 @@ class Signed_TestCase(unittest.TestCase): self.assertEqual(1, getargs_i(BadInt2())) self.assertEqual(0, getargs_i(BadInt3())) + self.assertRaises(OverflowError, getargs_i, -1 << 1000) self.assertRaises(OverflowError, getargs_i, INT_MIN-1) self.assertEqual(INT_MIN, getargs_i(INT_MIN)) self.assertEqual(INT_MAX, getargs_i(INT_MAX)) self.assertRaises(OverflowError, getargs_i, INT_MAX+1) + self.assertRaises(OverflowError, getargs_i, 1 << 1000) self.assertEqual(42, getargs_i(42)) self.assertRaises(OverflowError, getargs_i, VERY_LARGE) diff --git a/Objects/longobject.c b/Objects/longobject.c index 95661a4022..2c69fc8991 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -481,10 +481,15 @@ PyLong_AsLong(PyObject *obj) int overflow; long result = PyLong_AsLongAndOverflow(obj, &overflow); if (overflow) { - /* XXX: could be cute and give a different - message for overflow == -1 */ - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert to C long"); + if (overflow > 0) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C long"); + } + else { + assert(overflow < 0); + PyErr_SetString(PyExc_OverflowError, + "Python int too small to convert to C long"); + } } return result; } @@ -498,10 +503,15 @@ _PyLong_AsInt(PyObject *obj) int overflow; long result = PyLong_AsLongAndOverflow(obj, &overflow); if (overflow || result > INT_MAX || result < INT_MIN) { - /* XXX: could be cute and give a different - message for overflow == -1 */ - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert to C int"); + if (overflow > 0 || result > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int"); + } + else { + assert(overflow < 0 || result < INT_MIN); + PyErr_SetString(PyExc_OverflowError, + "Python int too small to convert to C int"); + } return -1; } return (int)result; @@ -557,8 +567,14 @@ PyLong_AsSsize_t(PyObject *vv) { /* else overflow */ overflow: - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert to C ssize_t"); + if (sign == 1) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C Py_ssize_t"); + } + else { + PyErr_SetString(PyExc_OverflowError, + "Python int too small to convert to C Py_ssize_t"); + } return -1; } @@ -586,7 +602,8 @@ PyLong_AsUnsignedLong(PyObject *vv) x = 0; if (i < 0) { PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to unsigned int"); + "can't convert negative Python int to C " + "unsigned long"); return (unsigned long) -1; } switch (i) { @@ -630,7 +647,7 @@ PyLong_AsSize_t(PyObject *vv) x = 0; if (i < 0) { PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to size_t"); + "can't convert negative Python int to C size_t"); return (size_t) -1; } switch (i) { @@ -642,7 +659,7 @@ PyLong_AsSize_t(PyObject *vv) x = (x << PyLong_SHIFT) | v->ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert to C size_t"); + "Python int too large to convert to C size_t"); return (size_t) -1; } } @@ -762,8 +779,9 @@ _PyLong_NumBits(PyObject *vv) return result; Overflow: - PyErr_SetString(PyExc_OverflowError, "int has too many bits " - "to express in a platform size_t"); + PyErr_SetString(PyExc_OverflowError, + "number of bits of Python int too large to express in C " + "size_t"); return (size_t)-1; } diff --git a/Python/getargs.c b/Python/getargs.c index 8cb672d6ab..b35e3e84b8 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -71,7 +71,8 @@ typedef struct { static int vgetargs1_impl(PyObject *args, PyObject **stack, Py_ssize_t nargs, const char *format, va_list *p_va, int flags); static int vgetargs1(PyObject *, const char *, va_list *, int); -static void seterror(Py_ssize_t, const char *, int *, const char *, const char *); +static void seterror(Py_ssize_t, const char *, int *, const char *, + const char *, const char *); static const char *convertitem(PyObject *, const char **, va_list *, int, int *, char *, size_t, freelist_t *); static const char *converttuple(PyObject *, const char **, va_list *, int, @@ -273,6 +274,7 @@ vgetargs1_impl(PyObject *compat_args, PyObject **stack, Py_ssize_t nargs, const freelist.first_available = 0; freelist.entries_malloced = 0; + assert(format != NULL); flags = flags & ~FLAG_COMPAT; while (endfmt == 0) { @@ -356,7 +358,7 @@ vgetargs1_impl(PyObject *compat_args, PyObject **stack, Py_ssize_t nargs, const msgbuf, sizeof(msgbuf), &freelist); if (msg == NULL) return cleanreturn(1, &freelist); - seterror(levels[0], msg, levels+1, fname, message); + seterror(levels[0], msg, levels+1, fname, message, format); return cleanreturn(0, &freelist); } else { @@ -389,7 +391,7 @@ vgetargs1_impl(PyObject *compat_args, PyObject **stack, Py_ssize_t nargs, const flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { - seterror(i+1, msg, levels, fname, message); + seterror(i+1, msg, levels, fname, message, format); return cleanreturn(0, &freelist); } } @@ -434,14 +436,21 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) static void seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname, - const char *message) + const char *message, const char *p_format_code) { char buf[512]; int i; char *p = buf; - if (PyErr_Occurred()) + if (PyErr_Occurred()) { + assert(p_format_code != NULL); + if (fname != NULL && PyErr_ExceptionMatches(PyExc_OverflowError) && + strchr("bhilLn", *p_format_code)) { + PyErr_Format(PyExc_OverflowError, + "%.150s() argument out of range", fname); + } return; + } else if (message == NULL) { if (fname != NULL) { PyOS_snprintf(p, sizeof(buf), "%.200s() ", fname); @@ -646,7 +655,11 @@ float_argument_error(PyObject *arg) When failing, an exception may or may not have been raised. Don't call if a tuple is expected. - When you add new format codes, please don't forget poor skipitem() below. + When you add new format codes, please don't forget poor skipitem() + below. + In case the new format code is for a conversion to an integer that + might overflow, please don't forget the strchr argument in poor + seterror() above. */ static const char * @@ -674,6 +687,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, const char *format = *p_format; char c = *format++; const char *sarg; + int overflow; switch (c) { @@ -682,17 +696,21 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, long ival; if (float_argument_error(arg)) RETURN_ERR_OCCURRED; - ival = PyLong_AsLong(arg); + ival = PyLong_AsLongAndOverflow(arg, &overflow); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; - else if (ival < 0) { - PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is less than minimum"); - RETURN_ERR_OCCURRED; - } - else if (ival > UCHAR_MAX) { - PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is greater than maximum"); + else if (overflow || ival > UCHAR_MAX || ival < 0) { + if (overflow > 0 || ival > UCHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C " + "unsigned char"); + } + else { + assert(overflow < 0 || ival < 0); + PyErr_SetString(PyExc_OverflowError, + "can't convert negative Python int to C " + "unsigned char"); + } RETURN_ERR_OCCURRED; } else @@ -719,17 +737,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, long ival; if (float_argument_error(arg)) RETURN_ERR_OCCURRED; - ival = PyLong_AsLong(arg); + ival = PyLong_AsLongAndOverflow(arg, &overflow); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; - else if (ival < SHRT_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - RETURN_ERR_OCCURRED; - } - else if (ival > SHRT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + else if (overflow || ival > SHRT_MAX || ival < SHRT_MIN) { + if (overflow > 0 || ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C short"); + } + else { + assert(overflow < 0 || ival < SHRT_MIN); + PyErr_SetString(PyExc_OverflowError, + "Python int too small to convert to C short"); + } RETURN_ERR_OCCURRED; } else @@ -753,22 +773,12 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, case 'i': {/* signed int */ int *p = va_arg(*p_va, int *); - long ival; + int ival; if (float_argument_error(arg)) RETURN_ERR_OCCURRED; - ival = PyLong_AsLong(arg); + ival = _PyLong_AsInt(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; - else if (ival > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "signed integer is greater than maximum"); - RETURN_ERR_OCCURRED; - } - else if (ival < INT_MIN) { - PyErr_SetString(PyExc_OverflowError, - "signed integer is less than minimum"); - RETURN_ERR_OCCURRED; - } else *p = ival; break; @@ -1735,7 +1745,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { - seterror(i+1, msg, levels, fname, custom_msg); + seterror(i+1, msg, levels, fname, custom_msg, format); return cleanreturn(0, &freelist); } continue; @@ -2077,6 +2087,7 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, } format = parser->format; + assert(format != NULL); /* convert tuple args and keyword args in same loop, using kwtuple to drive process */ for (i = 0; i < len; i++) { if (*format == '|') { @@ -2104,7 +2115,8 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { - seterror(i+1, msg, levels, parser->fname, parser->custom_msg); + seterror(i+1, msg, levels, parser->fname, parser->custom_msg, + format); return cleanreturn(0, &freelist); } continue;