Skip to content

Commit 2447773

Browse files
taleinatorenmn
andauthored
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 <[email protected]>
1 parent 121eb16 commit 2447773

File tree

3 files changed

+43
-10
lines changed

3 files changed

+43
-10
lines changed

Lib/ctypes/test/test_arrays.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,6 @@ class Y(T):
163163
self.assertEqual(Y()._length_, 187)
164164

165165
def test_bad_subclass(self):
166-
import sys
167-
168166
with self.assertRaises(AttributeError):
169167
class T(Array):
170168
pass
@@ -174,14 +172,30 @@ class T(Array):
174172
with self.assertRaises(AttributeError):
175173
class T(Array):
176174
_length_ = 13
177-
with self.assertRaises(OverflowError):
175+
176+
def test_bad_length(self):
177+
with self.assertRaises(ValueError):
178178
class T(Array):
179179
_type_ = c_int
180-
_length_ = sys.maxsize * 2
181-
with self.assertRaises(AttributeError):
180+
_length_ = - sys.maxsize * 2
181+
with self.assertRaises(ValueError):
182+
class T(Array):
183+
_type_ = c_int
184+
_length_ = -1
185+
with self.assertRaises(TypeError):
182186
class T(Array):
183187
_type_ = c_int
184188
_length_ = 1.87
189+
with self.assertRaises(OverflowError):
190+
class T(Array):
191+
_type_ = c_int
192+
_length_ = sys.maxsize * 2
193+
194+
def test_zero_length(self):
195+
# _length_ can be zero.
196+
class T(Array):
197+
_type_ = c_int
198+
_length_ = 0
185199

186200
@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
187201
@bigmemtest(size=_2G, memuse=1, dry_run=False)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Raise :exc:`ValueError` instead of :exc:`OverflowError` in case of a negative
2+
``_length_`` in a :class:`ctypes.Array` subclass. Also raise :exc:`TypeError`
3+
instead of :exc:`AttributeError` for non-integer ``_length_``.
4+
Original patch by Oren Milman.

Modules/_ctypes/_ctypes.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,13 +1405,28 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
14051405
type_attr = NULL;
14061406

14071407
length_attr = PyObject_GetAttrString((PyObject *)result, "_length_");
1408-
if (!length_attr || !PyLong_Check(length_attr)) {
1409-
PyErr_SetString(PyExc_AttributeError,
1410-
"class must define a '_length_' attribute, "
1411-
"which must be a positive integer");
1412-
Py_XDECREF(length_attr);
1408+
if (!length_attr) {
1409+
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
1410+
PyErr_SetString(PyExc_AttributeError,
1411+
"class must define a '_length_' attribute");
1412+
}
1413+
goto error;
1414+
}
1415+
1416+
if (!PyLong_Check(length_attr)) {
1417+
Py_DECREF(length_attr);
1418+
PyErr_SetString(PyExc_TypeError,
1419+
"The '_length_' attribute must be an integer");
14131420
goto error;
14141421
}
1422+
1423+
if (_PyLong_Sign(length_attr) == -1) {
1424+
Py_DECREF(length_attr);
1425+
PyErr_SetString(PyExc_ValueError,
1426+
"The '_length_' attribute must not be negative");
1427+
goto error;
1428+
}
1429+
14151430
length = PyLong_AsSsize_t(length_attr);
14161431
Py_DECREF(length_attr);
14171432
if (length == -1 && PyErr_Occurred()) {

0 commit comments

Comments
 (0)