diff --git a/Lib/ctypes/test/test_arrays.py b/Lib/ctypes/test/test_arrays.py index 6e562cfd24e663..9d50f18ec36937 100644 --- a/Lib/ctypes/test/test_arrays.py +++ b/Lib/ctypes/test/test_arrays.py @@ -183,6 +183,24 @@ class T(Array): _type_ = c_int _length_ = 1.87 + def test_bad_length(self): + with self.assertRaises(ValueError): + class T(Array): + _type_ = c_int + _length_ = -1 << 1000 + with self.assertRaises(ValueError): + class T(Array): + _type_ = c_int + _length_ = -1 + with self.assertRaises(OverflowError): + class T(Array): + _type_ = c_int + _length_ = 1 << 1000 + # _length_ might be zero. + class T(Array): + _type_ = c_int + _length_ = 0 + @unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform') @bigmemtest(size=_2G, memuse=1, dry_run=False) def test_large_array(self, size): diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-09-29-16-37-22.bpo-29843.RD5kyw.rst b/Misc/NEWS.d/next/Core and Builtins/2017-09-29-16-37-22.bpo-29843.RD5kyw.rst new file mode 100644 index 00000000000000..741f493d97e7ce --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-09-29-16-37-22.bpo-29843.RD5kyw.rst @@ -0,0 +1,2 @@ +Raise `ValueError` instead of `OverflowError` in case of a negative +``_length_`` in a `ctypes.Array` subclass. Patch by Oren Milman. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 3ae6348fef4317..4bef42e9438e4c 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1391,6 +1391,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) StgDictObject *itemdict; PyObject *length_attr, *type_attr; Py_ssize_t length; + int overflow; Py_ssize_t itemsize, itemalign; /* create the new instance (which is a class, @@ -1412,13 +1413,21 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_XDECREF(length_attr); goto error; } - length = PyLong_AsSsize_t(length_attr); + length = PyLong_AsLongAndOverflow(length_attr, &overflow); Py_DECREF(length_attr); - if (length == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + /* PyLong_Check(length_attr) is true, so it is guaranteed that + no error occurred in PyLong_AsLongAndOverflow(). */ + assert(!(length == -1 && PyErr_Occurred())); + if (overflow || length < 0) { + if (overflow > 0) { PyErr_SetString(PyExc_OverflowError, "The '_length_' attribute is too large"); } + else { + assert(overflow < 0 || length < 0); + PyErr_SetString(PyExc_ValueError, + "The '_length_' attribute must be non-negative"); + } goto error; }