]> granicus.if.org Git - python/commitdiff
bpo-29843: raise AttributeError if given negative _length_ (GH-10029)
authorTal Einat <taleinat+github@gmail.com>
Mon, 22 Oct 2018 15:33:10 +0000 (18:33 +0300)
committerGitHub <noreply@github.com>
Mon, 22 Oct 2018 15:33:10 +0000 (18:33 +0300)
Raise ValueError OverflowError in case of a negative
_length_ in a ctypes.Array subclass.  Also raise TypeError
instead of AttributeError for non-integer _length_.

Co-authored-by: Oren Milman <orenmn@gmail.com>
Lib/ctypes/test/test_arrays.py
Misc/NEWS.d/next/Core and Builtins/2018-10-21-17-43-48.bpo-29743.aeCcKR.rst [new file with mode: 0644]
Modules/_ctypes/_ctypes.c

index 6e562cfd24e6638c813188b83be6c408caeeead9..6cfda8b7d2e630e4b3e856508febc7578dc84f44 100644 (file)
@@ -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 (file)
index 0000000..9e79bb3
--- /dev/null
@@ -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.
index 3ae6348fef43179a48f4a2ea8cf2a92e7b37b76d..60f6985a6646dc7a9b9d2de124a675d9e1b8b632 100644 (file)
@@ -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()) {