summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2017-04-16 09:37:18 +0300
committerGitHub <noreply@github.com>2017-04-16 09:37:18 +0300
commitbaf9f29811dba9c06e76b8e220bd77260202f299 (patch)
tree2057d3d950d1411d7399929558745fd63230556a
parent813f943c592cf225871b99cffc99304c8cbbee40 (diff)
downloadcpython-git-baf9f29811dba9c06e76b8e220bd77260202f299.tar.gz
bpo-29839: Raise ValueError rather than OverflowError in len() for negative values. (#701)
-rw-r--r--Lib/test/test_builtin.py8
-rw-r--r--Misc/NEWS3
-rw-r--r--Objects/typeobject.c19
3 files changed, 24 insertions, 6 deletions
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index d2420e9dda..6613ca3a8c 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -770,10 +770,18 @@ class BuiltinTest(unittest.TestCase):
def __len__(self):
return 4.5
self.assertRaises(TypeError, len, FloatLen())
+ class NegativeLen:
+ def __len__(self):
+ return -10
+ self.assertRaises(ValueError, len, NegativeLen())
class HugeLen:
def __len__(self):
return sys.maxsize + 1
self.assertRaises(OverflowError, len, HugeLen())
+ class HugeNegativeLen:
+ def __len__(self):
+ return -sys.maxsize-10
+ self.assertRaises(ValueError, len, HugeNegativeLen())
class NoLenMethod(object): pass
self.assertRaises(TypeError, len, NoLenMethod())
diff --git a/Misc/NEWS b/Misc/NEWS
index da40d8f5a0..5981b3a1c7 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1?
Core and Builtins
-----------------
+- bpo-29839: len() now raises ValueError rather than OverflowError if
+ __len__() returned a large negative integer.
+
- bpo-11913: README.rst is now included in the list of distutils standard
READMEs and therefore included in source distributions.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index ed50946a26..89fe82c7c3 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -5924,14 +5924,21 @@ slot_sq_length(PyObject *self)
if (res == NULL)
return -1;
- len = PyNumber_AsSsize_t(res, PyExc_OverflowError);
- Py_DECREF(res);
- if (len < 0) {
- if (!PyErr_Occurred())
- PyErr_SetString(PyExc_ValueError,
- "__len__() should return >= 0");
+
+ Py_SETREF(res, PyNumber_Index(res));
+ if (res == NULL)
+ return -1;
+
+ assert(PyLong_Check(res));
+ if (Py_SIZE(res) < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "__len__() should return >= 0");
return -1;
}
+
+ len = PyNumber_AsSsize_t(res, PyExc_OverflowError);
+ assert(len >= 0 || PyErr_ExceptionMatches(PyExc_OverflowError));
+ Py_DECREF(res);
return len;
}