diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 2350125f6d6dbec..5c9bbee6438726a 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -711,6 +711,15 @@ def test_overflow(self): self.assertRaises(OverflowError, day.__truediv__, 1e-10) self.assertRaises(OverflowError, day.__truediv__, 9e-10) + # test overflow in timedelta constructor + self.assertRaises(OverflowError, timedelta, -1 << 1000) + self.assertRaises(OverflowError, timedelta, -999999999, 0, -1) + # no tests here for getting timedelta.min and timedelta.max from + # timedelta constructor, as these are already tested in + # test_resolution_info. + self.assertRaises(OverflowError, timedelta, 1e9) + self.assertRaises(OverflowError, timedelta, 1 << 1000) + @support.requires_IEEE_754 def _test_overflow_special(self): day = timedelta(1) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index cd3ee48a92bb7d3..3cab7cb55ceece1 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1140,6 +1140,24 @@ def test_mul(self): # 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 @@ -1237,6 +1255,14 @@ def test_formatting_c_limits(self): (PY_SSIZE_T_MAX + 1, '')) self.checkraises(OverflowError, '%.*f', '__mod__', (INT_MAX + 1, 1. / 7)) + + self.checkraises(OverflowError, '%c', '__mod__', -1 << 1000) + self.checkraises(OverflowError, '%c', '__mod__', -1) + self.checkequal('c=\x00', 'c=%c', '__mod__', 0) + self.checkequal('c=\U0010ffff', 'c=%c', '__mod__', 0x10ffff) + self.checkraises(OverflowError, '%c', '__mod__', 0x110000) + self.checkraises(OverflowError, '%c', '__mod__', 1 << 1000) + # Issue 15989 self.checkraises(OverflowError, '%*s', '__mod__', (SIZE_MAX + 1, '')) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 8a3b8055ff7d48e..5e6cdfcd701dd45 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -17,7 +17,7 @@ import test.support import test.string_tests import test.list_tests -from test.support import bigaddrspacetest, MAX_Py_ssize_t +from test.support import bigaddrspacetest, MAX_Py_ssize_t, cpython_only if sys.flags.bytes_warning: @@ -104,6 +104,16 @@ def test_from_ssize(self): self.assertEqual(self.type2test(b'0'), b'0') self.assertRaises(OverflowError, self.type2test, sys.maxsize + 1) + @cpython_only + def test_from_ssize_c_limits(self): + from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX + + self.assertRaises(OverflowError, self.type2test, -1 << 1000) + self.assertRaises(OverflowError, self.type2test, PY_SSIZE_T_MIN - 1) + self.assertRaises(ValueError, self.type2test, PY_SSIZE_T_MIN) + self.assertRaises(OverflowError, self.type2test, PY_SSIZE_T_MAX + 1) + self.assertRaises(OverflowError, self.type2test, 1 << 1000) + def test_constructor_type_errors(self): self.assertRaises(TypeError, self.type2test, 0.0) class C: @@ -905,6 +915,16 @@ def ptr_formatter(ptr): self.assertRaises(OverflowError, PyBytes_FromFormat, b'%c', c_int(256)) + self.assertRaises(OverflowError, b'%c'.__mod__, -1 << 1000) + self.assertRaises(OverflowError, b'%c'.__mod__, 1 << 1000) + + self.assertRaises(OverflowError, b'%c'.__mod__, Indexable(-1 << 1000)) + self.assertRaises(OverflowError, b'%c'.__mod__, Indexable(-1)) + self.assertEqual(b'c=%c' % Indexable(0), b'c=\0') + self.assertEqual(b'c=%c' % Indexable(255), b'c=\xff') + self.assertRaises(OverflowError, b'%c'.__mod__, Indexable(256)) + self.assertRaises(OverflowError, b'%c'.__mod__, Indexable(1 << 1000)) + def test_bytes_blocking(self): class IterationBlocked(list): __bytes__ = None diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 3d8c50bcb6c6ae4..e1aaa0de4b2ed44 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -15,7 +15,7 @@ import tempfile import unittest -from test.support import requires, import_module, verbose +from test.support import requires, import_module, verbose, cpython_only # Optionally test curses module. This currently requires that the # 'curses' resource be given on the regrtest command line using the -u @@ -194,6 +194,24 @@ def test_window_funcs(self): self.assertRaises(ValueError, stdscr.instr, -2) self.assertRaises(ValueError, stdscr.instr, 2, 3, -2) + @cpython_only + def test_getstr_and_instr_c_limits(self): + from _testcapi import INT_MIN, INT_MAX + + for meth in [self.stdscr.getstr, self.stdscr.instr]: + self.assertRaises(OverflowError, meth, -1 << 1000) + self.assertRaises(OverflowError, meth, 1, 1, -1 << 1000) + self.assertRaises(OverflowError, meth, INT_MIN - 1) + self.assertRaises(OverflowError, meth, 1, 1, INT_MIN - 1) + self.assertRaises(ValueError, meth, INT_MIN) + self.assertRaises(ValueError, meth, 1, 1, INT_MIN) + self.assertRaises(ValueError, meth, -1) + self.assertRaises(ValueError, meth, 1, 1, -1) + self.assertRaises(OverflowError, meth, INT_MAX + 1) + self.assertRaises(OverflowError, meth, 1, 1, INT_MAX + 1) + self.assertRaises(OverflowError, meth, 1 << 1000) + self.assertRaises(OverflowError, meth, 1, 1, 1 << 1000) + def test_module_funcs(self): "Test module-level functions" @@ -259,6 +277,18 @@ def test_colors_funcs(self): def test_keyname(self): curses.keyname(13) + @cpython_only + @requires_curses_func('keyname') + def test_keyname_c_limits(self): + from _testcapi import INT_MIN, INT_MAX + + self.assertRaises(OverflowError, curses.keyname, -1 << 1000) + self.assertRaises(OverflowError, curses.keyname, INT_MIN - 1) + self.assertRaises(ValueError, curses.keyname, INT_MIN) + self.assertRaises(ValueError, curses.keyname, -1) + self.assertRaises(OverflowError, curses.keyname, INT_MAX + 1) + self.assertRaises(OverflowError, curses.keyname, 1 << 1000) + @requires_curses_func('has_key') def test_has_key(self): curses.has_key(13) diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index 8a194aa03d42784..65f6ede3af8939a 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -140,10 +140,12 @@ def test_b(self): 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 @@ def test_h(self): 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 @@ def test_i(self): 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/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index f748b461907f6fb..5b6b077aceb67fa 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -873,6 +873,29 @@ def test_pbkdf2_hmac_py(self): def test_pbkdf2_hmac_c(self): self._test_pbkdf2_hmac(c_hashlib.pbkdf2_hmac) + @unittest.skipUnless(hasattr(c_hashlib, 'pbkdf2_hmac'), + ' test requires OpenSSL > 1.0') + @support.cpython_only + def test_pbkdf2_hmac_c_limits(self): + from _testcapi import LONG_MIN, INT_MAX + # test iterations limits + self.assertRaises(OverflowError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', -1 << 1000) + self.assertRaises(OverflowError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', LONG_MIN - 1) + self.assertRaises(ValueError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', LONG_MIN) + self.assertRaises(OverflowError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', INT_MAX + 1) + self.assertRaises(OverflowError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', 1 << 1000) + # test dklen limits + self.assertRaises(ValueError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', 1, -1 << 1000) + self.assertRaises(OverflowError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', 1, INT_MAX + 1) + self.assertRaises(OverflowError, c_hashlib.pbkdf2_hmac, + 'sha1', b'pass', b'salt', 1, 1 << 1000) @unittest.skipUnless(hasattr(c_hashlib, 'scrypt'), ' test requires OpenSSL > 1.1') diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index fd15f04aceca8fc..423dbe88f756739 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -712,6 +712,14 @@ def test__format__(self): self.assertEqual(format(value, format_spec), format(float(value), format_spec)) + # test 'c' specifier limits + self.assertRaises(OverflowError, format, -1 << 1000, 'c') + self.assertRaises(OverflowError, format, -1, 'c') + self.assertEqual(format(0, 'c'), '\x00') + self.assertEqual(format(0x10ffff, 'c'), '\U0010ffff') + self.assertRaises(OverflowError, format, 0x110000, 'c') + self.assertRaises(OverflowError, format, 1 << 1000, 'c') + def test_nan_inf(self): self.assertRaises(OverflowError, int, float('inf')) self.assertRaises(OverflowError, int, float('-inf')) @@ -921,6 +929,26 @@ def test_huge_lshift_of_zero(self): with self.assertRaises(OverflowError): 0 << (sys.maxsize + 1) + def test_negative_shift_count(self): + with self.assertRaises(ValueError): + 42 << -3 + with self.assertRaises(ValueError): + 42 >> -3 + + @support.cpython_only + def test_shift_c_limits(self): + from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX + + for zero_shifter in [(0).__lshift__, (0).__rshift__]: + self.assertRaises(OverflowError, zero_shifter, -1 << 1000) + self.assertRaises(OverflowError, zero_shifter, PY_SSIZE_T_MIN - 1) + self.assertRaises(ValueError, zero_shifter, PY_SSIZE_T_MIN) + self.assertRaises(ValueError, zero_shifter, -1) + self.assertEqual(zero_shifter(0), 0) + self.assertEqual(zero_shifter(PY_SSIZE_T_MAX), 0) + self.assertRaises(OverflowError, zero_shifter, PY_SSIZE_T_MAX + 1) + self.assertRaises(OverflowError, zero_shifter, 1 << 1000) + def test_small_ints(self): for i in range(-5, 257): self.assertIs(i, i + 0) diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py index d7a8576d512340d..e8a1f76cb40ea22 100644 --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -7,7 +7,7 @@ import unittest from test.support import ( - _4G, TESTFN, import_module, bigmemtest, run_unittest, unlink + _4G, TESTFN, import_module, bigmemtest, run_unittest, unlink, cpython_only ) lzma = import_module("lzma") @@ -58,6 +58,18 @@ def test_simple_bad_args(self): lzd.decompress(empty) self.assertRaises(EOFError, lzd.decompress, b"quux") + @cpython_only + def test_INT_TYPE_CONVERTER_FUNC_macro(self): + # test the macro by testing uint32_converter, which is created + # by using the macro, and is later used to convert the preset + # argument of LZMACompressor. + self.assertRaises(OverflowError, LZMACompressor, preset=-1 << 1000) + self.assertRaises(OverflowError, LZMACompressor, preset=-1) + LZMACompressor(preset=0) + self.assertRaises(LZMAError, LZMACompressor, preset=(1 << 32) - 1) + self.assertRaises(OverflowError, LZMACompressor, preset=1 << 32) + self.assertRaises(OverflowError, LZMACompressor, preset=1 << 1000) + def test_bad_filter_spec(self): self.assertRaises(TypeError, LZMACompressor, filters=[b"wobsite"]) self.assertRaises(ValueError, LZMACompressor, filters=[{"xyzzy": 3}]) diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py index 80055ce1e7d8d16..e995ac1c8162c40 100644 --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -778,6 +778,20 @@ def test_cow_mutable(self): memio = self.ioclass(ba) self.assertEqual(sys.getrefcount(ba), old_rc) + @support.cpython_only + def test_truncate_c_limits(self): + from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX + memio = self.ioclass() + + self.assertRaises(OverflowError, memio.truncate, -1 << 1000) + self.assertRaises(OverflowError, memio.truncate, PY_SSIZE_T_MIN - 1) + self.assertRaises(ValueError, memio.truncate, PY_SSIZE_T_MIN) + self.assertRaises(ValueError, memio.truncate, -1) + memio.truncate(0) + memio.truncate(PY_SSIZE_T_MAX) + self.assertRaises(OverflowError, memio.truncate, PY_SSIZE_T_MAX + 1) + self.assertRaises(OverflowError, memio.truncate, 1 << 1000) + class CStringIOTest(PyStringIOTest): ioclass = io.StringIO UnsupportedOperation = io.UnsupportedOperation @@ -825,6 +839,20 @@ def test_setstate(self): memio.close() self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None)) + @support.cpython_only + def test_truncate_c_limits(self): + from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX + memio = self.ioclass() + + self.assertRaises(OverflowError, memio.truncate, -1 << 1000) + self.assertRaises(OverflowError, memio.truncate, PY_SSIZE_T_MIN - 1) + self.assertRaises(ValueError, memio.truncate, PY_SSIZE_T_MIN) + self.assertRaises(ValueError, memio.truncate, -1) + memio.truncate(0) + memio.truncate(PY_SSIZE_T_MAX) + self.assertRaises(OverflowError, memio.truncate, PY_SSIZE_T_MAX + 1) + self.assertRaises(OverflowError, memio.truncate, 1 << 1000) + class CStringIOPickleTest(PyStringIOPickleTest): UnsupportedOperation = io.UnsupportedOperation diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 56d85e75f87a937..a8b332e5835094f 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -417,6 +417,30 @@ def test_anonymous(self): m[x] = b self.assertEqual(m[x], b) + def test_bad_length(self): + self.assertRaises(OverflowError, mmap.mmap, -1, -1 << 1000) + self.assertRaises(OverflowError, mmap.mmap, -1, -1) + + @cpython_only + def test_constructor_c_limits(self): + from _testcapi import INT_MIN, INT_MAX, PY_SSIZE_T_MAX + + # test overflow values of arguments that are stored in the + # same C types on Unix and on Windows: + # fileno + self.assertRaises(OverflowError, mmap.mmap, -1 << 1000, 16) + self.assertRaises(OverflowError, mmap.mmap, INT_MIN - 1, 16) + self.assertRaises(OverflowError, mmap.mmap, INT_MAX + 1, 16) + self.assertRaises(OverflowError, mmap.mmap, 1 << 1000, 16) + # length + self.assertRaises(OverflowError, mmap.mmap, -1, PY_SSIZE_T_MAX + 1) + self.assertRaises(OverflowError, mmap.mmap, -1, 1 << 1000) + # access + self.assertRaises(OverflowError, mmap.mmap, -1, 16, access=-1 << 1000) + self.assertRaises(OverflowError, mmap.mmap, -1, 16, access=INT_MIN - 1) + self.assertRaises(OverflowError, mmap.mmap, -1, 16, access=INT_MAX + 1) + self.assertRaises(OverflowError, mmap.mmap, -1, 16, access=1 << 1000) + def test_read_all(self): m = mmap.mmap(-1, 16) self.addCleanup(m.close) @@ -446,6 +470,19 @@ def test_read_invalid_arg(self): self.assertRaises(TypeError, m.read, 5.5) self.assertRaises(TypeError, m.read, [1, 2, 3]) + @cpython_only + def test_read_c_limits(self): + from _testcapi import PY_SSIZE_T_MAX, PY_SSIZE_T_MIN + m = mmap.mmap(-1, 16) + self.addCleanup(m.close) + + self.assertRaises(OverflowError, m.read, -1 << 1000) + self.assertRaises(OverflowError, m.read, PY_SSIZE_T_MIN - 1) + m.read(PY_SSIZE_T_MIN) + m.read(PY_SSIZE_T_MAX) + self.assertRaises(OverflowError, m.read, PY_SSIZE_T_MAX + 1) + self.assertRaises(OverflowError, m.read, 1 << 1000) + def test_extended_getslice(self): # Test extended slicing by comparing with list slicing. s = bytes(reversed(range(256))) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 029d0815e945898..9aba7e07bd7b3de 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1095,6 +1095,25 @@ def test_get_and_set_scheduler_and_param(self): param = posix.sched_param(sched_priority=-large) self.assertRaises(OverflowError, posix.sched_setparam, 0, param) + @support.cpython_only + @unittest.skipUnless(hasattr(posix, 'sched_setparam'), + "can't change scheduler params") + def test_convert_sched_param_c_limits(self): + from _testcapi import INT_MIN, INT_MAX + orig_param = posix.sched_getparam(0) + self.addCleanup(posix.sched_setparam, 0, orig_param) + + for bad_val in [-1 << 1000, INT_MIN - 1, INT_MAX + 1, 1 << 1000]: + bad_param = posix.sched_param(bad_val) + self.assertRaises(OverflowError, + posix.sched_setparam, 0, bad_param) + # verify OverflowError is not raised + for in_range_int in [INT_MIN, INT_MAX]: + try: + posix.sched_setparam(0, posix.sched_param(in_range_int)) + except OSError: + pass + @unittest.skipUnless(hasattr(posix, "sched_rr_get_interval"), "no function") def test_sched_rr_get_interval(self): try: @@ -1131,9 +1150,28 @@ def test_sched_setaffinity(self): self.assertEqual(posix.sched_getaffinity(0), mask) self.assertRaises(OSError, posix.sched_setaffinity, 0, []) self.assertRaises(ValueError, posix.sched_setaffinity, 0, [-10]) + self.assertRaises(ValueError, posix.sched_setaffinity, 0, [-1]) self.assertRaises(OverflowError, posix.sched_setaffinity, 0, [1<<128]) self.assertRaises(OSError, posix.sched_setaffinity, -1, mask) + @support.cpython_only + @requires_sched_affinity + def test_sched_setaffinity_c_limits(self): + from _testcapi import INT_MAX + orig_mask = posix.sched_getaffinity(0) + self.addCleanup(posix.sched_setaffinity, 0, orig_mask) + + self.assertRaises(ValueError, posix.sched_setaffinity, 0, [-1 << 1000]) + # verify OverflowError is not raised + try: + posix.sched_setaffinity(0, [INT_MAX - 1]) + except OSError: + pass + self.assertRaises(OverflowError, + posix.sched_setaffinity, 0, [INT_MAX]) + self.assertRaises(OverflowError, + posix.sched_setaffinity, 0, [1 << 1000]) + def test_rtld_constants(self): # check presence of major RTLD_* constants posix.RTLD_LAZY diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 1d7fb76c3833960..6d68c32c6c06f67 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1507,6 +1507,27 @@ def test_dealloc(self): with self.assertRaises(TypeError): _sre.compile({}, 0, [], 0, [], []) + @cpython_only + def test_sre_compile_c_limits(self): + import _sre + # Currently SRE_CODE is an alias for Py_UCS4, which is an + # alias for uint32_t. + + with self.assertRaises(OverflowError): + _sre.compile("abc", 0, [-1 << 1000], 0, {}, tuple()) + with self.assertRaises(OverflowError): + _sre.compile("abc", 0, [-1], 0, {}, tuple()) + # verify OverflowError is not raised + for in_range_code in [0, (1 << 32) - 1]: + try: + _sre.compile("abc", 0, [in_range_code], 0, {}, tuple()) + except RuntimeError: + pass + with self.assertRaises(OverflowError): + _sre.compile("abc", 0, [1 << 32], 0, {}, tuple()) + with self.assertRaises(OverflowError): + _sre.compile("abc", 0, [1 << 1000], 0, {}, tuple()) + def test_search_dot_unicode(self): self.assertTrue(re.search("123.*-", '123abc-')) self.assertTrue(re.search("123.*-", '123\xe9-')) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index f8e5b369ef23b6c..a23b99077d54e5e 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1234,11 +1234,21 @@ def testNewAttributes(self): def test_getsockaddrarg(self): sock = socket.socket() self.addCleanup(sock.close) - port = support.find_unused_port() - big_port = port + 65536 - neg_port = port - 65536 - self.assertRaises(OverflowError, sock.bind, (HOST, big_port)) - self.assertRaises(OverflowError, sock.bind, (HOST, neg_port)) + + self.assertRaises(OverflowError, sock.bind, (HOST, -1 << 1000)) + self.assertRaises(OverflowError, sock.bind, (HOST, -1)) + # verify OverflowError is not raised + for in_range_port in [0, 0xffff]: + try: + sock.bind((HOST, in_range_port)) + except OSError: + pass + else: + sock = socket.socket() + self.addCleanup(sock.close) + self.assertRaises(OverflowError, sock.bind, (HOST, 1 << 16)) + self.assertRaises(OverflowError, sock.bind, (HOST, 1 << 1000)) + # Since find_unused_port() is inherently subject to race conditions, we # call it a couple times if necessary. for i in itertools.count(): @@ -1495,6 +1505,12 @@ def test_listen_backlog_overflow(self): @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') def test_flowinfo(self): + self.assertRaises(OverflowError, + socket.getnameinfo, (support.HOSTv6, 0, -1), 0) + socket.getnameinfo((support.HOSTv6, 0, 0), 0) + socket.getnameinfo((support.HOSTv6, 0, (1 << 20) - 1), 0) + self.assertRaises(OverflowError, + socket.getnameinfo, (support.HOSTv6, 0, 1 << 20), 0) self.assertRaises(OverflowError, socket.getnameinfo, (support.HOSTv6, 0, 0xffffffff), 0) with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s: diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index cd02a6ee37452b9..56115b71ceec2f3 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,25 @@ class TestFilemodeCStat(TestFilemode, unittest.TestCase): format_funcs = TestFilemode.format_funcs | {'S_ISDOOR', 'S_ISPORT', 'S_ISWHT'} + @cpython_only + def test_mode_t_converter(self): + from _testcapi import USHRT_MAX + + # 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) + + # test platform specific mode_t upper limit + if sys.platform == 'win32': + 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/Misc/NEWS b/Misc/NEWS index 72404b3ac2413d6..b3282b14436a83d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1? Core and Builtins ----------------- +- bpo-15988: Make various overflow error messages (in various files) more + consistent and helpful. + - bpo-29723: The ``sys.path[0]`` initialization change for bpo-29139 caused a regression by revealing an inconsistency in how sys.path is initialized when executing ``__main__`` from a zipfile, directory, or other import location. diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c index ec9e3c14b0bc71d..467d7d4770de30b 100644 --- a/Modules/_blake2/blake2b_impl.c +++ b/Modules/_blake2/blake2b_impl.c @@ -159,6 +159,10 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, if (leaf_size_obj != NULL) { leaf_size = PyLong_AsUnsignedLong(leaf_size_obj); if (leaf_size == (unsigned long) -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "leaf_size must be between 0 and 2**32-1"); + } goto error; } if (leaf_size > 0xFFFFFFFFU) { diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c index 42257a24fdfce00..1227f1176956364 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -159,6 +159,10 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, if (leaf_size_obj != NULL) { leaf_size = PyLong_AsUnsignedLong(leaf_size_obj); if (leaf_size == (unsigned long) -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "leaf_size must be between 0 and 2**32-1"); + } goto error; } if (leaf_size > 0xFFFFFFFFU) { diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 9d42109b516ba9e..64e4acb12ab6c48 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1351,7 +1351,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) length = PyLong_AsLongAndOverflow(length_attr, &overflow); if (overflow) { PyErr_SetString(PyExc_OverflowError, - "The '_length_' attribute is too large"); + "The '_length_' attribute does not fit in C long"); Py_DECREF(length_attr); goto error; } diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 9b368caf65b58c0..e55da5b1bb80dc7 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 4d714cecdfb9545..298693a4108a579 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; @@ -1217,8 +1221,9 @@ PyCursesWindow_GetStr(PyCursesWindowObject *self, PyObject *args) Py_END_ALLOW_THREADS break; case 1: - if (!PyArg_ParseTuple(args,"i;n", &n)) + if (!PyArg_ParseTuple(args, "i:getstr", &n)) { return NULL; + } if (n < 0) { PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative"); return NULL; @@ -1228,8 +1233,9 @@ PyCursesWindow_GetStr(PyCursesWindowObject *self, PyObject *args) Py_END_ALLOW_THREADS break; case 2: - if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x)) + if (!PyArg_ParseTuple(args, "ii:getstr", &y, &x)) { return NULL; + } Py_BEGIN_ALLOW_THREADS #ifdef STRICT_SYSV_CURSES rtn2 = wmove(self->win,y,x)==ERR ? ERR : wgetnstr(self->win, rtn, 1023); @@ -1239,8 +1245,9 @@ PyCursesWindow_GetStr(PyCursesWindowObject *self, PyObject *args) Py_END_ALLOW_THREADS break; case 3: - if (!PyArg_ParseTuple(args,"iii;y,x,n", &y, &x, &n)) + if (!PyArg_ParseTuple(args, "iii:getstr", &y, &x, &n)) { return NULL; + } if (n < 0) { PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative"); return NULL; @@ -1389,8 +1396,9 @@ PyCursesWindow_InStr(PyCursesWindowObject *self, PyObject *args) rtn2 = winnstr(self->win,rtn, 1023); break; case 1: - if (!PyArg_ParseTuple(args,"i;n", &n)) + if (!PyArg_ParseTuple(args, "i:instr", &n)) { return NULL; + } if (n < 0) { PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative"); return NULL; @@ -1398,13 +1406,15 @@ PyCursesWindow_InStr(PyCursesWindowObject *self, PyObject *args) rtn2 = winnstr(self->win, rtn, Py_MIN(n, 1023)); break; case 2: - if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x)) + if (!PyArg_ParseTuple(args, "ii:instr", &y, &x)) { return NULL; + } rtn2 = mvwinnstr(self->win,y,x,rtn,1023); break; case 3: - if (!PyArg_ParseTuple(args, "iii;y,x,n", &y, &x, &n)) + if (!PyArg_ParseTuple(args, "iii:instr", &y, &x, &n)) { return NULL; + } if (n < 0) { PyErr_SetString(PyExc_ValueError, "'n' must be nonnegative"); return NULL; @@ -2588,10 +2598,12 @@ PyCurses_KeyName(PyObject *self, PyObject *args) PyCursesInitialised; - if (!PyArg_ParseTuple(args,"i",&ch)) return NULL; + if (!PyArg_ParseTuple(args, "i:keyname" ,&ch)) { + return NULL; + } if (ch < 0) { - PyErr_SetString(PyExc_ValueError, "invalid key number"); + PyErr_SetString(PyExc_ValueError, "key number must be nonnegative"); return NULL; } knp = keyname(ch); @@ -3089,15 +3101,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/_datetimemodule.c b/Modules/_datetimemodule.c index 1803d85a7123f1d..845174903b7c521 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1616,13 +1616,10 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) if (num == NULL) goto Done; Py_INCREF(num); - temp = PyLong_AsLong(num); - if (temp == -1 && PyErr_Occurred()) - goto Done; - d = (int)temp; - if ((long)d != temp) { - PyErr_SetString(PyExc_OverflowError, "normalized days too " - "large to fit in a C int"); + d = _PyLong_AsInt(num); + if (d == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_OverflowError, + "normalized days does not fit in C int"); goto Done; } result = new_delta_ex(d, s, us, 0, type); @@ -2184,7 +2181,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) "minutes", "hours", "weeks", NULL }; - if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:__new__", + if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:timedelta.__new__", keywords, &day, &second, &us, &ms, &minute, &hour, &week) == 0) @@ -2531,7 +2528,7 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw) return (PyObject *)me; } - if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws, + if (PyArg_ParseTupleAndKeywords(args, kw, "iii:date.__new__", date_kws, &year, &month, &day)) { self = new_date_ex(year, month, day, type); } @@ -3615,7 +3612,8 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) return (PyObject *)me; } - if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws, + if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i:time.__new__", + time_kws, &hour, &minute, &second, &usecond, &tzinfo, &fold)) { self = new_time_ex2(hour, minute, second, usecond, tzinfo, fold, @@ -4201,7 +4199,8 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) return (PyObject *)me; } - if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws, + if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i:datetime.__new__", + datetime_kws, &year, &month, &day, &hour, &minute, &second, &usecond, &tzinfo, &fold)) { self = new_datetime_ex2(year, month, day, diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 49952947cba20f5..dec8e156a2ad274 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -629,6 +629,7 @@ pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict) long iterations, dklen; int retval; const EVP_MD *digest; + int overflow; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "sy*y*l|O:pbkdf2_hmac", kwlist, &name, &password, &salt, @@ -668,20 +669,20 @@ pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict) if (dklen_obj == Py_None) { dklen = EVP_MD_size(digest); } else { - dklen = PyLong_AsLong(dklen_obj); - if ((dklen == -1) && PyErr_Occurred()) { + dklen = PyLong_AsLongAndOverflow(dklen_obj, &overflow); + if (dklen == -1 && PyErr_Occurred()) { goto end; } } - if (dklen < 1) { - PyErr_SetString(PyExc_ValueError, - "key length must be greater than 0."); - goto end; - } - if (dklen > INT_MAX) { + if (overflow == 1 || dklen > INT_MAX) { /* INT_MAX is always smaller than dkLen max (2^32 - 1) * hLen */ PyErr_SetString(PyExc_OverflowError, - "key length is too great."); + "key length is too large."); + goto end; + } + if (overflow == -1 || dklen < 1) { + PyErr_SetString(PyExc_ValueError, + "key length must be greater than 0."); goto end; } diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 59b917d0bdaaa16..2d9f2e7d929dc4b 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -581,6 +581,10 @@ _io_BytesIO_truncate_impl(bytesio *self, PyObject *arg) else if (PyIndex_Check(arg)) { size = PyNumber_AsSsize_t(arg, PyExc_OverflowError); if (size == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "size value does not fit in C Py_ssize_t"); + } return NULL; } } diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index a73171fd8f602c8..164146cbbf5f607 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -461,6 +461,10 @@ _io_StringIO_truncate_impl(stringio *self, PyObject *arg) if (PyIndex_Check(arg)) { size = PyNumber_AsSsize_t(arg, PyExc_OverflowError); if (size == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "size value does not fit in C Py_ssize_t"); + } return NULL; } } diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index bb77552b67b15dd..21841f3dbde4a21 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -166,22 +166,28 @@ grow_buffer(PyObject **buf, Py_ssize_t max_length) to be strictly correct, we need to define two separate converters. */ -#define INT_TYPE_CONVERTER_FUNC(TYPE, FUNCNAME) \ - static int \ - FUNCNAME(PyObject *obj, void *ptr) \ - { \ - unsigned long long val; \ - \ - val = PyLong_AsUnsignedLongLong(obj); \ - if (PyErr_Occurred()) \ - return 0; \ - if ((unsigned long long)(TYPE)val != val) { \ - PyErr_SetString(PyExc_OverflowError, \ - "Value too large for " #TYPE " type"); \ - return 0; \ - } \ - *(TYPE *)ptr = (TYPE)val; \ - return 1; \ +#define INT_TYPE_CONVERTER_FUNC(TYPE, FUNCNAME) \ + static int \ + FUNCNAME(PyObject *obj, void *ptr) \ + { \ + unsigned long long val; \ + \ + val = PyLong_AsUnsignedLongLong(obj); \ + if (val == (unsigned long long)-1 && PyErr_Occurred()) { \ + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) { \ + return 0; \ + } \ + } \ + else if ((unsigned long long)(TYPE)val == val) { \ + *(TYPE *)ptr = (TYPE)val; \ + return 1; \ + } \ + \ + /* Either PyExc_OverflowError occurred in \ + PyLong_AsUnsignedLongLong, or val didn't fit in TYPE. */ \ + PyErr_SetString(PyExc_OverflowError, \ + "Python int does not fit in C " #TYPE); \ + return 0; \ } INT_TYPE_CONVERTER_FUNC(uint32_t, uint32_converter) diff --git a/Modules/_pickle.c b/Modules/_pickle.c index e65b88e9c0739ae..1df63c144052de9 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1812,9 +1812,12 @@ save_long(PicklerObject *self, PyObject *obj) const char long_op = LONG; + assert(PyLong_CheckExact(obj)); val= PyLong_AsLong(obj); if (val == -1 && PyErr_Occurred()) { - /* out of range for int pickling */ + /* PyLong_Check(obj) is true, so it must be that + PyLong_AsLong raised an OverflowError, i.e. obj is out + of range for int pickling */ PyErr_Clear(); } else if (self->bin && @@ -1875,8 +1878,12 @@ save_long(PicklerObject *self, PyObject *obj) return 0; } nbits = _PyLong_NumBits(obj); - if (nbits == (size_t)-1 && PyErr_Occurred()) + if (nbits == (size_t)-1 && PyErr_Occurred()) { + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "Python int too large to pickle"); goto error; + } /* How many bytes do we need? There are nbits >> 3 full * bytes of data, and nbits & 7 leftover bits. If there * are any leftover bits, then we clearly need another @@ -1894,7 +1901,7 @@ save_long(PicklerObject *self, PyObject *obj) nbytes = (nbits >> 3) + 1; if (nbytes > 0x7fffffffL) { PyErr_SetString(PyExc_OverflowError, - "int too large to pickle"); + "Python int too large to pickle"); goto error; } repr = PyBytes_FromStringAndSize(NULL, (Py_ssize_t)nbytes); diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index b371aed99dbe4db..954cdd4ee56fc53 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -151,6 +151,6 @@ _pysqlite_long_as_int64(PyObject * py_val) } } PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert to SQLite INTEGER"); + "Python int does not fit in C sqlite_int64"); return -1; } diff --git a/Modules/_sre.c b/Modules/_sre.c index 2a2fd272c41f3d7..f11e35997105ad1 100644 --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1414,12 +1414,16 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, self->code[i] = (SRE_CODE) value; if ((unsigned long) self->code[i] != value) { PyErr_SetString(PyExc_OverflowError, - "regular expression code size limit exceeded"); + "regular expression code out of range"); break; } } if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "regular expression code out of range"); + } Py_DECREF(self); return NULL; } diff --git a/Modules/_stat.c b/Modules/_stat.c index f6cb303500cd140..12ff9d08224599c 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/Modules/arraymodule.c b/Modules/arraymodule.c index b30f7594c25a24a..e74a5acee398a5e 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -197,20 +197,22 @@ b_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) /* PyArg_Parse's 'b' formatter is for an unsigned char, therefore must use the next size up that is signed ('h') and manually do the overflow checking */ - if (!PyArg_Parse(v, "h;array item must be integer", &x)) + if (!PyArg_Parse(v, "h:array('b').__setitem__", &x)) { return -1; + } else if (x < -128) { PyErr_SetString(PyExc_OverflowError, - "signed char is less than minimum"); + "array item too small to convert to C char"); return -1; } else if (x > 127) { PyErr_SetString(PyExc_OverflowError, - "signed char is greater than maximum"); + "array item too large to convert to C char"); return -1; } - if (i >= 0) + if (i >= 0) { ((char *)ap->ob_item)[i] = (char)x; + } return 0; } @@ -226,10 +228,12 @@ BB_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) { unsigned char x; /* 'B' == unsigned char, maps to PyArg_Parse's 'b' formatter */ - if (!PyArg_Parse(v, "b;array item must be integer", &x)) + if (!PyArg_Parse(v, "b:array('B').__setitem__", &x)) { return -1; - if (i >= 0) + } + if (i >= 0) { ((char *)ap->ob_item)[i] = x; + } return 0; } @@ -270,10 +274,12 @@ h_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) { short x; /* 'h' == signed short, maps to PyArg_Parse's 'h' formatter */ - if (!PyArg_Parse(v, "h;array item must be integer", &x)) + if (!PyArg_Parse(v, "h:array('h').__setitem__", &x)) { return -1; - if (i >= 0) - ((short *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((short *)ap->ob_item)[i] = x; + } return 0; } @@ -289,20 +295,22 @@ HH_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) int x; /* PyArg_Parse's 'h' formatter is for a signed short, therefore must use the next size up and manually do the overflow checking */ - if (!PyArg_Parse(v, "i;array item must be integer", &x)) + if (!PyArg_Parse(v, "i:array('H').__setitem__", &x)) { return -1; + } else if (x < 0) { PyErr_SetString(PyExc_OverflowError, - "unsigned short is less than minimum"); + "array item can't be negative"); return -1; } else if (x > USHRT_MAX) { PyErr_SetString(PyExc_OverflowError, - "unsigned short is greater than maximum"); + "array item too large to convert to C unsigned short"); return -1; } - if (i >= 0) + if (i >= 0) { ((short *)ap->ob_item)[i] = (short)x; + } return 0; } @@ -317,10 +325,12 @@ i_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) { int x; /* 'i' == signed int, maps to PyArg_Parse's 'i' formatter */ - if (!PyArg_Parse(v, "i;array item must be integer", &x)) + if (!PyArg_Parse(v, "i:array('i').__setitem__", &x)) { return -1; - if (i >= 0) - ((int *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((int *)ap->ob_item)[i] = x; + } return 0; } @@ -357,6 +367,9 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } x = PyLong_AsUnsignedLong(v); if (x == (unsigned long)-1 && PyErr_Occurred()) { + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "array item does not fit in C unsigned int"); if (do_decref) { Py_DECREF(v); } @@ -364,14 +377,15 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } if (x > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, - "unsigned int is greater than maximum"); + "array item too large to convert to C unsigned int"); if (do_decref) { Py_DECREF(v); } return -1; } - if (i >= 0) + if (i >= 0) { ((unsigned int *)ap->ob_item)[i] = (unsigned int)x; + } if (do_decref) { Py_DECREF(v); @@ -389,10 +403,12 @@ static int l_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) { long x; - if (!PyArg_Parse(v, "l;array item must be integer", &x)) + if (!PyArg_Parse(v, "l:array('l').__setitem__", &x)) { return -1; - if (i >= 0) - ((long *)ap->ob_item)[i] = x; + } + if (i >= 0) { + ((long *)ap->ob_item)[i] = x; + } return 0; } @@ -417,13 +433,17 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } x = PyLong_AsUnsignedLong(v); if (x == (unsigned long)-1 && PyErr_Occurred()) { + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "array item does not fit in C unsigned long"); if (do_decref) { Py_DECREF(v); } return -1; } - if (i >= 0) + if (i >= 0) { ((unsigned long *)ap->ob_item)[i] = x; + } if (do_decref) { Py_DECREF(v); @@ -441,10 +461,12 @@ static int q_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) { long long x; - if (!PyArg_Parse(v, "L;array item must be integer", &x)) + if (!PyArg_Parse(v, "L:array('q').__setitem__", &x)) { return -1; - if (i >= 0) + } + if (i >= 0) { ((long long *)ap->ob_item)[i] = x; + } return 0; } @@ -470,13 +492,17 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } x = PyLong_AsUnsignedLongLong(v); if (x == (unsigned long long)-1 && PyErr_Occurred()) { + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "array item does not fit in C unsigned long long"); if (do_decref) { Py_DECREF(v); } return -1; } - if (i >= 0) + if (i >= 0) { ((unsigned long long *)ap->ob_item)[i] = x; + } if (do_decref) { Py_DECREF(v); diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 7c15d377cfdf4ee..b0ea9a192e54d28 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -271,8 +271,15 @@ mmap_read_method(mmap_object *self, PyObject *result; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes)) + if (!PyArg_ParseTuple(args, "|O&:read", + mmap_convert_ssize_t, &num_bytes)) { + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "read count does not fit in C Py_ssize_t"); + } return(NULL); + } /* silently 'adjust' out-of-range requests */ remaining = (self->pos < self->size) ? self->size - self->pos : 0; @@ -1084,18 +1091,20 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) "flags", "prot", "access", "offset", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, - &fd, &map_size, &flags, &prot, - &access, &offset)) + if (!PyArg_ParseTupleAndKeywords(args, kwdict, + "in|iii" _Py_PARSE_OFF_T ":mmap.__new__", + keywords, &fd, &map_size, &flags, &prot, + &access, &offset)) { return NULL; + } if (map_size < 0) { PyErr_SetString(PyExc_OverflowError, - "memory mapped length must be postiive"); + "memory mapped length must be positive"); return NULL; } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, - "memory mapped offset must be positive"); + "memory mapped offset must be positive"); return NULL; } @@ -1244,8 +1253,8 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) "tagname", "access", "offset", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, - &fileno, &map_size, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL:mmap.__new__", + keywords, &fileno, &map_size, &tagname, &access, &offset)) { return NULL; } @@ -1270,12 +1279,12 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) if (map_size < 0) { PyErr_SetString(PyExc_OverflowError, - "memory mapped length must be postiive"); + "memory mapped length must be positive"); return NULL; } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, - "memory mapped offset must be positive"); + "memory mapped offset must be positive"); return NULL; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0ae06eb53eaef9d..8df420dbacd78d0 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5415,20 +5415,21 @@ static PyStructSequence_Desc sched_param_desc = { static int convert_sched_param(PyObject *param, struct sched_param *res) { - long priority; + int priority; if (Py_TYPE(param) != &SchedParamType) { PyErr_SetString(PyExc_TypeError, "must have a sched_param object"); return 0; } - priority = PyLong_AsLong(PyStructSequence_GET_ITEM(param, 0)); - if (priority == -1 && PyErr_Occurred()) - return 0; - if (priority > INT_MAX || priority < INT_MIN) { - PyErr_SetString(PyExc_OverflowError, "sched_priority out of range"); + priority = _PyLong_AsInt(PyStructSequence_GET_ITEM(param, 0)); + if (priority == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "sched_priority value does not fit in C int"); + } return 0; } - res->sched_priority = Py_SAFE_DOWNCAST(priority, long, int); + res->sched_priority = priority; return 1; } #endif /* defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SCHED_SETPARAM) */ @@ -5584,7 +5585,7 @@ static PyObject * os_sched_setaffinity_impl(PyObject *module, pid_t pid, PyObject *mask) /*[clinic end generated code: output=882d7dd9a229335b input=a0791a597c7085ba]*/ { - int ncpus; + int ncpus, overflow; size_t setsize; cpu_set_t *cpu_set = NULL; PyObject *iterator = NULL, *item; @@ -5612,15 +5613,17 @@ os_sched_setaffinity_impl(PyObject *module, pid_t pid, PyObject *mask) Py_DECREF(item); goto error; } - cpu = PyLong_AsLong(item); + cpu = PyLong_AsLongAndOverflow(item, &overflow); + /* PyLong_Check(item) is true, so it is guaranteed that + no error occurred in PyLong_AsLongAndOverflow. */ + assert(!(cpu == -1 && PyErr_Occurred())); Py_DECREF(item); - if (cpu < 0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_ValueError, "negative CPU number"); + if (overflow == 1 || cpu > INT_MAX - 1) { + PyErr_SetString(PyExc_OverflowError, "CPU number too large"); goto error; } - if (cpu > INT_MAX - 1) { - PyErr_SetString(PyExc_OverflowError, "CPU number too large"); + if (overflow == -1 || cpu < 0) { + PyErr_SetString(PyExc_ValueError, "negative CPU number"); goto error; } if (cpu >= ncpus) { diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 6f71d5855685f3f..a9dce9178a39ab5 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -384,7 +384,7 @@ ushort_converter(PyObject *obj, void *ptr) return 0; if (uval > USHRT_MAX) { PyErr_SetString(PyExc_OverflowError, - "Python int too large for C unsigned short"); + "Python int too large to convert to C unsigned short"); return 0; } @@ -407,8 +407,16 @@ poll_register(pollObject *self, PyObject *args) unsigned short events = POLLIN | POLLPRI | POLLOUT; int err; - if (!PyArg_ParseTuple(args, "O|O&:register", &o, ushort_converter, &events)) + if (!PyArg_ParseTuple(args, "O|O&:register", + &o, ushort_converter, &events)) { + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "eventmask value does not fit in C " + "unsigned short"); + } return NULL; + } fd = PyObject_AsFileDescriptor(o); if (fd == -1) return NULL; @@ -449,8 +457,16 @@ poll_modify(pollObject *self, PyObject *args) unsigned short events; int err; - if (!PyArg_ParseTuple(args, "OO&:modify", &o, ushort_converter, &events)) + if (!PyArg_ParseTuple(args, "OO&:modify", + &o, ushort_converter, &events)) { + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "eventmask value does not fit in C " + "unsigned short"); + } return NULL; + } fd = PyObject_AsFileDescriptor(o); if (fd == -1) return NULL; @@ -787,8 +803,16 @@ internal_devpoll_register(devpollObject *self, PyObject *args, int remove) if (self->fd_devpoll < 0) return devpoll_err_closed(); - if (!PyArg_ParseTuple(args, "O|O&:register", &o, ushort_converter, &events)) + if (!PyArg_ParseTuple(args, "O|O&:register/modify", + &o, ushort_converter, &events)) { + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "eventmask value does not fit in C " + "unsigned short"); + } return NULL; + } fd = PyObject_AsFileDescriptor(o); if (fd == -1) return NULL; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 63e87e6e4867ee0..1572059ce713802 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1635,7 +1635,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, Py_TYPE(args)->tp_name); return 0; } - if (!PyArg_ParseTuple(args, "O&i|II", + if (!PyArg_ParseTuple(args, "O&i|II:getsockaddrarg", idna_converter, &host, &port, &flowinfo, &scope_id)) { return 0; @@ -1782,10 +1782,10 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, Py_TYPE(args)->tp_name); return 0; } - if (!PyArg_ParseTuple(args, "si|iiy*", &interfaceName, - &protoNumber, &pkttype, &hatype, - &haddr)) + if (!PyArg_ParseTuple(args, "si|iiy*:getsockaddrarg", &interfaceName, + &protoNumber, &pkttype, &hatype, &haddr)) { return 0; + } strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { @@ -5514,8 +5514,13 @@ socket_ntohl(PyObject *self, PyObject *arg) if (PyLong_Check(arg)) { x = PyLong_AsUnsignedLong(arg); - if (x == (unsigned long) -1 && PyErr_Occurred()) + if (x == (unsigned long) -1 && PyErr_Occurred()) { + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "ntohl: Python int does not fit in C 32-bit " + "unsigned integer"); return NULL; + } #if SIZEOF_LONG > 4 { unsigned long y; @@ -5523,7 +5528,8 @@ socket_ntohl(PyObject *self, PyObject *arg) y = x & 0xFFFFFFFFUL; if (y ^ x) return PyErr_Format(PyExc_OverflowError, - "int larger than 32 bits"); + "ntohl: Python int too large to convert " + "to C 32-bit unsigned integer"); x = y; } #endif @@ -5585,8 +5591,13 @@ socket_htonl(PyObject *self, PyObject *arg) if (PyLong_Check(arg)) { x = PyLong_AsUnsignedLong(arg); - if (x == (unsigned long) -1 && PyErr_Occurred()) + if (x == (unsigned long) -1 && PyErr_Occurred()) { + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "htonl: Python int does not fit in C 32-bit " + "unsigned integer"); return NULL; + } #if SIZEOF_LONG > 4 { unsigned long y; @@ -5594,7 +5605,8 @@ socket_htonl(PyObject *self, PyObject *arg) y = x & 0xFFFFFFFFUL; if (y ^ x) return PyErr_Format(PyExc_OverflowError, - "int larger than 32 bits"); + "htonl: Python int too large to convert " + "to C 32-bit unsigned integer"); x = y; } #endif @@ -5603,7 +5615,7 @@ socket_htonl(PyObject *self, PyObject *arg) return PyErr_Format(PyExc_TypeError, "expected int, %s found", Py_TYPE(arg)->tp_name); - return PyLong_FromUnsignedLong(htonl((unsigned long)x)); + return PyLong_FromUnsignedLong(htonl(x)); } PyDoc_STRVAR(htonl_doc, @@ -6082,12 +6094,13 @@ socket_getnameinfo(PyObject *self, PyObject *args) "getnameinfo() argument 1 must be a tuple"); return NULL; } - if (!PyArg_ParseTuple(sa, "si|II", - &hostp, &port, &flowinfo, &scope_id)) + if (!PyArg_ParseTuple(sa, "si|II:getnameinfo", + &hostp, &port, &flowinfo, &scope_id)) { return NULL; + } if (flowinfo > 0xfffff) { PyErr_SetString(PyExc_OverflowError, - "getsockaddrarg: flowinfo must be 0-1048575."); + "getnameinfo: flowinfo must be 0-1048575."); return NULL; } PyOS_snprintf(pbuf, sizeof(pbuf), "%d", port); diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 25eb92dada14363..da51fdf92c307b3 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -427,11 +427,12 @@ gettmarg(PyObject *args, struct tm *p) return 0; } - if (!PyArg_ParseTuple(args, "iiiiiiiii", + if (!PyArg_ParseTuple(args, "iiiiiiiii:mktime/asctime/strftime", &y, &p->tm_mon, &p->tm_mday, &p->tm_hour, &p->tm_min, &p->tm_sec, - &p->tm_wday, &p->tm_yday, &p->tm_isdst)) + &p->tm_wday, &p->tm_yday, &p->tm_isdst)) { return 0; + } p->tm_year = y - 1900; p->tm_mon--; p->tm_wday = (p->tm_wday + 1) % 7; diff --git a/Objects/abstract.c b/Objects/abstract.c index 4a75b92e1d08954..8b89ea4befc85e7 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 " diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 3a80b73e0be4fca..a49a2dbe62bff38 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -798,8 +798,11 @@ bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds) if (PyIndex_Check(arg)) { count = PyNumber_AsSsize_t(arg, PyExc_OverflowError); if (count == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "count does not fit in C Py_ssize_t"); return -1; + } PyErr_Clear(); /* fall through */ } else { diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index c4ef4957771d782..4f22a193aeaa75c 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -505,15 +505,23 @@ byte_converter(PyObject *arg, char *p) else { iobj = PyNumber_Index(arg); if (iobj == NULL) { - if (!PyErr_ExceptionMatches(PyExc_TypeError)) + assert(PyErr_Occurred()); + if (!PyErr_ExceptionMatches(PyExc_TypeError)) { return 0; - goto onError; + } + PyErr_SetString(PyExc_TypeError, + "%c requires an integer in range(256) or a " + "single byte"); + return 0; } ival = PyLong_AsLongAndOverflow(iobj, &overflow); Py_DECREF(iobj); } - if (!overflow && ival == -1 && PyErr_Occurred()) - goto onError; + /* If we reached here, PyLong_AsLongAndOverflow was called + for an object such that PyLong_Check(object) is true, so + it is guaranteed that no error occurred in it. */ + assert(!(ival == -1 && PyErr_Occurred())); + if (overflow || !(0 <= ival && ival <= 255)) { PyErr_SetString(PyExc_OverflowError, "%c arg not in range(256)"); @@ -522,10 +530,6 @@ byte_converter(PyObject *arg, char *p) *p = (char)ival; return 1; } - onError: - PyErr_SetString(PyExc_TypeError, - "%c requires an integer in range(256) or a single byte"); - return 0; } static PyObject * @@ -2593,8 +2597,11 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (PyIndex_Check(x)) { size = PyNumber_AsSsize_t(x, PyExc_OverflowError); if (size == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "count does not fit in C Py_ssize_t"); return NULL; + } PyErr_Clear(); /* fall through */ } else { diff --git a/Objects/longobject.c b/Objects/longobject.c index 95661a4022018f4..19ff15a1ccfcdf0 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -480,12 +480,14 @@ 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 */ + if (overflow == 1) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C long"); } + else if (overflow == -1) { + PyErr_SetString(PyExc_OverflowError, + "Python int too small to convert to C long"); + } return result; } @@ -497,13 +499,16 @@ _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 */ + if (overflow == 1 || result > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C int"); return -1; } + else if (overflow == -1 || result < INT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "Python int too small to convert to C int"); + return -1; + } return (int)result; } @@ -557,8 +562,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 +597,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 +642,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 +654,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 +774,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; } @@ -4309,11 +4322,17 @@ long_rshift(PyLongObject *a, PyLongObject *b) } else { shiftby = PyLong_AsSsize_t((PyObject *)b); - if (shiftby == -1L && PyErr_Occurred()) + if (shiftby == -1L && PyErr_Occurred()) { + /* PyLong_Check(b) is true, so it must be that + PyLong_AsSsize_t raised an OverflowError. */ + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "shift count does not fit in C Py_ssize_t"); return NULL; + } if (shiftby < 0) { PyErr_SetString(PyExc_ValueError, - "negative shift count"); + "shift count can't be negative"); return NULL; } wordshift = shiftby / PyLong_SHIFT; @@ -4350,10 +4369,16 @@ long_lshift(PyObject *v, PyObject *w) CHECK_BINOP(a, b); shiftby = PyLong_AsSsize_t((PyObject *)b); - if (shiftby == -1L && PyErr_Occurred()) + if (shiftby == -1L && PyErr_Occurred()) { + /* PyLong_Check(b) is true, so it must be that + PyLong_AsSsize_t raised an OverflowError. */ + assert(PyErr_ExceptionMatches(PyExc_OverflowError)); + PyErr_SetString(PyExc_OverflowError, + "shift count does not fit in C Py_ssize_t"); return NULL; + } if (shiftby < 0) { - PyErr_SetString(PyExc_ValueError, "negative shift count"); + PyErr_SetString(PyExc_ValueError, "shift count can't be negative"); return NULL; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 503a59e1ef1336e..12228fd57211042 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14373,6 +14373,7 @@ mainformatlong(PyObject *v, static Py_UCS4 formatchar(PyObject *v) { + int overflow; /* presume that the buffer is at least 3 characters long */ if (PyUnicode_Check(v)) { if (PyUnicode_GET_LENGTH(v) == 1) { @@ -14389,16 +14390,17 @@ formatchar(PyObject *v) if (iobj == NULL) { goto onError; } - x = PyLong_AsLong(iobj); + x = PyLong_AsLongAndOverflow(iobj, &overflow); Py_DECREF(iobj); } else { - x = PyLong_AsLong(v); + x = PyLong_AsLongAndOverflow(v, &overflow); } - if (x == -1 && PyErr_Occurred()) - goto onError; + /* either PyLong_Check(v) or PyLong_Check(iobj) is true, so it is + guaranteed that no error occurred in PyLong_AsLongAndOverflow. */ + assert(!(x == -1 && PyErr_Occurred())); - if (x < 0 || x > MAX_UNICODE) { + if (overflow || x < 0 || x > MAX_UNICODE) { PyErr_SetString(PyExc_OverflowError, "%c arg not in range(0x110000)"); return (Py_UCS4) -1; diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c index a2c2b3627c9ec74..f20d077e14141b9 100644 --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -860,6 +860,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format, Py_ssize_t prefix = 0; NumberFieldWidths spec; long x; + int overflow; /* Locale settings, either from the actual locale or from a hard-code pseudo-locale */ @@ -889,12 +890,12 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format, goto done; } - /* taken from unicodeobject.c formatchar() */ /* Integer input truncated to a character */ - x = PyLong_AsLong(value); - if (x == -1 && PyErr_Occurred()) + x = PyLong_AsLongAndOverflow(value, &overflow); + if (x == -1 && PyErr_Occurred()) { goto done; - if (x < 0 || x > 0x10ffff) { + } + if (overflow || x < 0 || x > 0x10ffff) { PyErr_SetString(PyExc_OverflowError, "%c arg not in range(0x110000)"); goto done; diff --git a/Python/getargs.c b/Python/getargs.c index 8cb672d6abc38af..f1df9f81c5fadcc 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,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 < 0) { + else if (overflow == 1 || ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is less than minimum"); + "Python int too large to convert to C unsigned " + "char"); RETURN_ERR_OCCURRED; } - else if (ival > UCHAR_MAX) { + else if (overflow == -1 || ival < 0) { PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is greater than maximum"); + "can't convert negative Python int to C unsigned " + "char"); RETURN_ERR_OCCURRED; } else @@ -719,17 +735,17 @@ 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) { + else if (overflow == 1 || ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); + "Python int too large to convert to C short"); RETURN_ERR_OCCURRED; } - else if (ival > SHRT_MAX) { + else if (overflow == -1 || ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); + "Python int too small to convert to C short"); RETURN_ERR_OCCURRED; } else @@ -753,22 +769,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 +1741,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 +2083,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 +2111,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;