diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 56d85e75f8..a8b332e583 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -417,6 +417,30 @@ class MmapTests(unittest.TestCase): 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 @@ class MmapTests(unittest.TestCase): 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 029d0815e9..9aba7e07bd 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1095,6 +1095,25 @@ class PosixTester(unittest.TestCase): 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 @@ class PosixTester(unittest.TestCase): 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/Modules/mmapmodule.c b/Modules/mmapmodule.c index 7c15d377cf..209a9b6117 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", + 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 non-negative"); return NULL; } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, - "memory mapped offset must be positive"); + "memory mapped offset must be non-negative"); 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", + 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 non-negative"); return NULL; } if (offset < 0) { PyErr_SetString(PyExc_OverflowError, - "memory mapped offset must be positive"); + "memory mapped offset must be non-negative"); return NULL; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0ae06eb53e..e8c55d40b1 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,19 @@ 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()) + if (overflow || cpu > INT_MAX - 1 || cpu < 0) { + if (overflow > 0 || cpu > INT_MAX - 1) { + PyErr_SetString(PyExc_OverflowError, "CPU number too large"); + } + else { + assert(overflow < 0 || cpu < 0); PyErr_SetString(PyExc_ValueError, "negative CPU number"); - goto error; - } - if (cpu > INT_MAX - 1) { - PyErr_SetString(PyExc_OverflowError, "CPU number too large"); + } goto error; } if (cpu >= ncpus) { diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 6f71d58556..b47349bca4 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -380,11 +380,16 @@ ushort_converter(PyObject *obj, void *ptr) unsigned long uval; uval = PyLong_AsUnsignedLong(obj); - if (uval == (unsigned long)-1 && PyErr_Occurred()) + if (uval == (unsigned long)-1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "Python int does not fit in C unsigned short"); + } 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; } diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 63e87e6e48..bcb3406cd1 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5476,6 +5476,12 @@ socket_ntohs(PyObject *self, PyObject *args) int x; if (!PyArg_ParseTuple(args, "i:ntohs", &x)) { + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "ntohs: Python int does not fit in C 16-bit " + "unsigned integer"); + } return NULL; } if (x < 0) { @@ -5514,8 +5520,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 +5534,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 does not fit in " + "C 32-bit unsigned integer"); x = y; } #endif @@ -5547,6 +5559,12 @@ socket_htons(PyObject *self, PyObject *args) int x; if (!PyArg_ParseTuple(args, "i:htons", &x)) { + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_OverflowError, + "htons: Python int does not fit in C 16-bit " + "unsigned integer"); + } return NULL; } if (x < 0) { @@ -5585,8 +5603,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 +5617,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 does not fit in " + "C 32-bit unsigned integer"); x = y; } #endif @@ -5603,7 +5627,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,