Skip to content

Commit baf9f29

Browse files
bpo-29839: Raise ValueError rather than OverflowError in len() for negative values. (#701)
1 parent 813f943 commit baf9f29

File tree

3 files changed

+24
-6
lines changed

3 files changed

+24
-6
lines changed

Lib/test/test_builtin.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,10 +770,18 @@ class FloatLen:
770770
def __len__(self):
771771
return 4.5
772772
self.assertRaises(TypeError, len, FloatLen())
773+
class NegativeLen:
774+
def __len__(self):
775+
return -10
776+
self.assertRaises(ValueError, len, NegativeLen())
773777
class HugeLen:
774778
def __len__(self):
775779
return sys.maxsize + 1
776780
self.assertRaises(OverflowError, len, HugeLen())
781+
class HugeNegativeLen:
782+
def __len__(self):
783+
return -sys.maxsize-10
784+
self.assertRaises(ValueError, len, HugeNegativeLen())
777785
class NoLenMethod(object): pass
778786
self.assertRaises(TypeError, len, NoLenMethod())
779787

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- bpo-29839: len() now raises ValueError rather than OverflowError if
14+
__len__() returned a large negative integer.
15+
1316
- bpo-11913: README.rst is now included in the list of distutils standard
1417
READMEs and therefore included in source distributions.
1518

Objects/typeobject.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5924,14 +5924,21 @@ slot_sq_length(PyObject *self)
59245924

59255925
if (res == NULL)
59265926
return -1;
5927-
len = PyNumber_AsSsize_t(res, PyExc_OverflowError);
5928-
Py_DECREF(res);
5929-
if (len < 0) {
5930-
if (!PyErr_Occurred())
5931-
PyErr_SetString(PyExc_ValueError,
5932-
"__len__() should return >= 0");
5927+
5928+
Py_SETREF(res, PyNumber_Index(res));
5929+
if (res == NULL)
5930+
return -1;
5931+
5932+
assert(PyLong_Check(res));
5933+
if (Py_SIZE(res) < 0) {
5934+
PyErr_SetString(PyExc_ValueError,
5935+
"__len__() should return >= 0");
59335936
return -1;
59345937
}
5938+
5939+
len = PyNumber_AsSsize_t(res, PyExc_OverflowError);
5940+
assert(len >= 0 || PyErr_ExceptionMatches(PyExc_OverflowError));
5941+
Py_DECREF(res);
59355942
return len;
59365943
}
59375944

0 commit comments

Comments
 (0)