summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/ctypes/test/test_arrays.py24
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2018-10-21-17-43-48.bpo-29743.aeCcKR.rst4
-rw-r--r--Modules/_ctypes/_ctypes.c25
3 files changed, 43 insertions, 10 deletions
diff --git a/Lib/ctypes/test/test_arrays.py b/Lib/ctypes/test/test_arrays.py
index 6e562cf..6cfda8b 100644
--- a/Lib/ctypes/test/test_arrays.py
+++ b/Lib/ctypes/test/test_arrays.py
@@ -163,8 +163,6 @@ class ArrayTestCase(unittest.TestCase):
self.assertEqual(Y()._length_, 187)
def test_bad_subclass(self):
- import sys
-
with self.assertRaises(AttributeError):
class T(Array):
pass
@@ -174,14 +172,30 @@ class ArrayTestCase(unittest.TestCase):
with self.assertRaises(AttributeError):
class T(Array):
_length_ = 13
- with self.assertRaises(OverflowError):
+
+ def test_bad_length(self):
+ with self.assertRaises(ValueError):
class T(Array):
_type_ = c_int
- _length_ = sys.maxsize * 2
- with self.assertRaises(AttributeError):
+ _length_ = - sys.maxsize * 2
+ with self.assertRaises(ValueError):
+ class T(Array):
+ _type_ = c_int
+ _length_ = -1
+ with self.assertRaises(TypeError):
class T(Array):
_type_ = c_int
_length_ = 1.87
+ with self.assertRaises(OverflowError):
+ class T(Array):
+ _type_ = c_int
+ _length_ = sys.maxsize * 2
+
+ def test_zero_length(self):
+ # _length_ can 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)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-10-21-17-43-48.bpo-29743.aeCcKR.rst b/Misc/NEWS.d/next/Core and Builtins/2018-10-21-17-43-48.bpo-29743.aeCcKR.rst
new file mode 100644
index 0000000..9e79bb3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-10-21-17-43-48.bpo-29743.aeCcKR.rst
@@ -0,0 +1,4 @@
+Raise :exc:`ValueError` instead of :exc:`OverflowError` in case of a negative
+``_length_`` in a :class:`ctypes.Array` subclass. Also raise :exc:`TypeError`
+instead of :exc:`AttributeError` for non-integer ``_length_``.
+Original patch by Oren Milman.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 3ae6348..60f6985 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -1405,13 +1405,28 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
type_attr = NULL;
length_attr = PyObject_GetAttrString((PyObject *)result, "_length_");
- if (!length_attr || !PyLong_Check(length_attr)) {
- PyErr_SetString(PyExc_AttributeError,
- "class must define a '_length_' attribute, "
- "which must be a positive integer");
- Py_XDECREF(length_attr);
+ if (!length_attr) {
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_SetString(PyExc_AttributeError,
+ "class must define a '_length_' attribute");
+ }
+ goto error;
+ }
+
+ if (!PyLong_Check(length_attr)) {
+ Py_DECREF(length_attr);
+ PyErr_SetString(PyExc_TypeError,
+ "The '_length_' attribute must be an integer");
goto error;
}
+
+ if (_PyLong_Sign(length_attr) == -1) {
+ Py_DECREF(length_attr);
+ PyErr_SetString(PyExc_ValueError,
+ "The '_length_' attribute must not be negative");
+ goto error;
+ }
+
length = PyLong_AsSsize_t(length_attr);
Py_DECREF(length_attr);
if (length == -1 && PyErr_Occurred()) {