diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index cd3ee48a92..d36ae0c298 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1140,6 +1140,24 @@ class MixinStrUnicodeUserStringTest: # but either raises a MemoryError, or succeeds (if you have 54TiB) #self.checkraises(OverflowError, 10000*'abc', '__mul__', 2000000000) + @support.cpython_only + def test_mul_c_limits(self): + from _testcapi import PY_SSIZE_T_MAX, PY_SSIZE_T_MIN + + # the following tests also test sequence_repeat in Objects/abstract.c + self.checkraises(OverflowError, '', '__mul__', -1 << 1000) + self.checkraises(OverflowError, '', '__mul__', PY_SSIZE_T_MIN - 1) + self.checkequal('', 'a', '__mul__', PY_SSIZE_T_MIN) + self.checkequal('', '', '__mul__', PY_SSIZE_T_MAX) + self.checkraises(OverflowError, '', '__mul__', PY_SSIZE_T_MAX + 1) + self.checkraises(OverflowError, '', '__mul__', 1 << 1000) + + # result's length can't be bigger than PY_SSIZE_T_MAX + self.checkraises(OverflowError, + 'ab', '__mul__', PY_SSIZE_T_MAX // 2 + 1) + self.checkraises(OverflowError, + 'ab' * 0x1000, '__mul__', PY_SSIZE_T_MAX) + def test_join(self): # join now works with any sequence type # moved here, because the argument order is diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index cd02a6ee37..7baa1c781c 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -1,7 +1,8 @@ import unittest import os import sys -from test.support import TESTFN, import_fresh_module, android_not_root +from test.support import (TESTFN, import_fresh_module, android_not_root, + cpython_only) c_stat = import_fresh_module('stat', fresh=['_stat']) py_stat = import_fresh_module('stat', blocked=['_stat']) @@ -223,6 +224,26 @@ class TestFilemodeCStat(TestFilemode, unittest.TestCase): format_funcs = TestFilemode.format_funcs | {'S_ISDOOR', 'S_ISPORT', 'S_ISWHT'} + @cpython_only + def test_mode_t_converter(self): + # test _PyLong_AsMode_t by testing S_IMODE, which uses + # _PyLong_AsMode_t to convert the argument it receives. + self.assertRaises(TypeError, c_stat.S_IMODE, 1.0) + self.assertRaises(TypeError, c_stat.S_IMODE, '1') + + self.assertRaises(OverflowError, c_stat.S_IMODE, -1 << 1000) + self.assertRaises(OverflowError, c_stat.S_IMODE, -1) + c_stat.S_IMODE(0) + self.assertRaises(OverflowError, c_stat.S_IMODE, 1 << 1000) + + @cpython_only + @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') + def test_mode_t_converter_windows(self): + from _testcapi import USHRT_MAX + + c_stat.S_IMODE(USHRT_MAX) # verify OverflowError is not raised + self.assertRaises(OverflowError, c_stat.S_IMODE, USHRT_MAX + 1) + class TestFilemodePyStat(TestFilemode, unittest.TestCase): statmod = py_stat diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 9b368caf65..e55da5b1bb 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -650,7 +650,8 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa) pa->value.i = PyLong_AsLong(obj); if (pa->value.i == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, - "int too long to convert"); + "Python int fits neither C unsigned long nor " + "C long"); return -1; } } diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 4d714cecdf..0b70a53353 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -244,6 +244,8 @@ PyCurses_ConvertToChtype(PyCursesWindowObject *win, PyObject *obj, chtype *ch) else if (PyLong_CheckExact(obj)) { int long_overflow; value = PyLong_AsLongAndOverflow(obj, &long_overflow); + /* PyLong_Check(obj) is true, so it is guaranteed that + no error occurred in PyLong_AsLongAndOverflow. */ if (long_overflow) goto overflow; } @@ -260,7 +262,7 @@ PyCurses_ConvertToChtype(PyCursesWindowObject *win, PyObject *obj, chtype *ch) overflow: PyErr_SetString(PyExc_OverflowError, - "byte doesn't fit in chtype"); + "Python object does not fit in C chtype"); return 0; } @@ -309,9 +311,11 @@ PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj, else if (PyLong_CheckExact(obj)) { int overflow; value = PyLong_AsLongAndOverflow(obj, &overflow); + /* PyLong_Check(obj) is true, so it is guaranteed that + no error occurred in PyLong_AsLongAndOverflow. */ if (overflow) { PyErr_SetString(PyExc_OverflowError, - "int doesn't fit in long"); + "Python int does not fit in C chtype"); return 0; } } @@ -325,7 +329,7 @@ PyCurses_ConvertToCchar_t(PyCursesWindowObject *win, PyObject *obj, *ch = (chtype)value; if ((long)*ch != value) { PyErr_Format(PyExc_OverflowError, - "byte doesn't fit in chtype"); + "Python object does not fit in C chtype"); return 0; } return 1; @@ -2591,7 +2595,7 @@ PyCurses_KeyName(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args,"i",&ch)) return NULL; if (ch < 0) { - PyErr_SetString(PyExc_ValueError, "invalid key number"); + PyErr_SetString(PyExc_ValueError, "key number must be non-negative"); return NULL; } knp = keyname(ch); @@ -3089,15 +3093,17 @@ PyCurses_ConvertToWchar_t(PyObject *obj, long value; int overflow; value = PyLong_AsLongAndOverflow(obj, &overflow); + /* PyLong_Check(obj) is true, so it is guaranteed that + no error occurred in PyLong_AsLongAndOverflow. */ if (overflow) { PyErr_SetString(PyExc_OverflowError, - "int doesn't fit in long"); + "Python int does not fit in C wchar_t"); return 0; } *wch = (wchar_t)value; if ((long)*wch != value) { PyErr_Format(PyExc_OverflowError, - "character doesn't fit in wchar_t"); + "Python int does not fit in C wchar_t"); return 0; } return 1; diff --git a/Modules/_stat.c b/Modules/_stat.c index f6cb303500..12ff9d0822 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -251,12 +251,18 @@ _PyLong_AsMode_t(PyObject *op) mode_t mode; value = PyLong_AsUnsignedLong(op); - if ((value == (unsigned long)-1) && PyErr_Occurred()) + if ((value == (unsigned long)-1) && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "Python int does not fit in C mode_t"); + } return (mode_t)-1; + } mode = (mode_t)value; if ((unsigned long)mode != value) { - PyErr_SetString(PyExc_OverflowError, "mode out of range"); + PyErr_SetString(PyExc_OverflowError, + "Python int does not fit in C mode_t"); return (mode_t)-1; } return mode; diff --git a/Objects/abstract.c b/Objects/abstract.c index 4a75b92e1d..8b89ea4bef 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -936,8 +936,14 @@ sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) Py_ssize_t count; if (PyIndex_Check(n)) { count = PyNumber_AsSsize_t(n, PyExc_OverflowError); - if (count == -1 && PyErr_Occurred()) + if (count == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "sequence repeat count does not fit in C " + "Py_ssize_t"); + } return NULL; + } } else { return type_error("can't multiply sequence by "