bpo-29843: raise AttributeError if given negative _length_ (GH-10029)

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>
This commit is contained in:
Tal Einat 2018-10-22 18:33:10 +03:00 committed by GitHub
parent 121eb1694c
commit 2447773573
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 11 deletions

View File

@ -163,8 +163,6 @@ class ArrayTestCase(unittest.TestCase):
self.assertEqual(Y()._length_, 187) self.assertEqual(Y()._length_, 187)
def test_bad_subclass(self): def test_bad_subclass(self):
import sys
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
class T(Array): class T(Array):
pass pass
@ -174,14 +172,30 @@ class ArrayTestCase(unittest.TestCase):
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
class T(Array): class T(Array):
_length_ = 13 _length_ = 13
def test_bad_length(self):
with self.assertRaises(ValueError):
class T(Array):
_type_ = c_int
_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): with self.assertRaises(OverflowError):
class T(Array): class T(Array):
_type_ = c_int _type_ = c_int
_length_ = sys.maxsize * 2 _length_ = sys.maxsize * 2
with self.assertRaises(AttributeError):
class T(Array): def test_zero_length(self):
_type_ = c_int # _length_ can be zero.
_length_ = 1.87 class T(Array):
_type_ = c_int
_length_ = 0
@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform') @unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
@bigmemtest(size=_2G, memuse=1, dry_run=False) @bigmemtest(size=_2G, memuse=1, dry_run=False)

View File

@ -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.

View File

@ -1405,13 +1405,28 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
type_attr = NULL; type_attr = NULL;
length_attr = PyObject_GetAttrString((PyObject *)result, "_length_"); length_attr = PyObject_GetAttrString((PyObject *)result, "_length_");
if (!length_attr || !PyLong_Check(length_attr)) { if (!length_attr) {
PyErr_SetString(PyExc_AttributeError, if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
"class must define a '_length_' attribute, " PyErr_SetString(PyExc_AttributeError,
"which must be a positive integer"); "class must define a '_length_' attribute");
Py_XDECREF(length_attr); }
goto error; 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); length = PyLong_AsSsize_t(length_attr);
Py_DECREF(length_attr); Py_DECREF(length_attr);
if (length == -1 && PyErr_Occurred()) { if (length == -1 && PyErr_Occurred()) {