From 1872b1c01f343f4cbfa7696ce95beae8278ce210 Mon Sep 17 00:00:00 2001
From: Neal Norwitz <nnorwitz@gmail.com>
Date: Sat, 12 Aug 2006 18:44:06 +0000
Subject: Fix a couple of bugs exposed by the new __index__ code.  The 64-bit
 buildbots were failing due to inappropriate clipping of numbers larger than
 2**31 with new-style classes. (typeobject.c)  In reviewing the code for
 classic classes, there were 2 problems.  Any negative value return could be
 returned. Always return -1 if there was an error.  Also make the checks
 similar with the new-style classes.  I believe this is correct for 32 and 64
 bit boxes, including Windows64.

Add a test of classic classes too.
---
 Lib/test/test_index.py | 11 +++++++++--
 Misc/NEWS              |  6 ++++++
 Objects/classobject.c  | 13 +++++++------
 Objects/typeobject.c   |  8 +++-----
 4 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/Lib/test/test_index.py b/Lib/test/test_index.py
index b224a50..1081b53 100644
--- a/Lib/test/test_index.py
+++ b/Lib/test/test_index.py
@@ -181,8 +181,8 @@ class OverflowTestCase(unittest.TestCase):
         self.assertEqual(self.pos.__index__(), self.pos)
         self.assertEqual(self.neg.__index__(), self.neg)
 
-    def test_getitem(self):
-        class GetItem(object):
+    def _getitem_helper(self, base):
+        class GetItem(base):
             def __len__(self):
                 return maxint
             def __getitem__(self, key):
@@ -195,6 +195,13 @@ class OverflowTestCase(unittest.TestCase):
         self.assertEqual(x[self.neg:self.pos], (-1, maxint))
         self.assertEqual(x[self.neg:self.pos:1].indices(maxint), (0, maxint, 1))
 
+    def test_getitem(self):
+        self._getitem_helper(object)
+
+    def test_getitem_classic(self):
+        class Empty: pass
+        self._getitem_helper(Empty)
+
     def test_sequence_repeat(self):
         self.failUnlessRaises(OverflowError, lambda: "a" * self.pos)
         self.failUnlessRaises(OverflowError, lambda: "a" * self.neg)
diff --git a/Misc/NEWS b/Misc/NEWS
index 49de4b6..f81389d 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,12 @@ What's New in Python 2.5 release candidate 1?
 Core and builtins
 -----------------
 
+- Fix bug related to __len__ functions using values > 2**32 on 64-bit machines
+  with new-style classes.
+  
+- Fix bug related to __len__ functions returning negative values with
+  classic classes.
+  
 - Patch #1538606, Fix __index__() clipping.  There were some problems
   discovered with the API and how integers that didn't fit into Py_ssize_t
   were handled.  This patch attempts to provide enough alternatives
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 1e93908..e8bac91 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -974,24 +974,25 @@ instance_length(PyInstanceObject *inst)
 	if (res == NULL)
 		return -1;
 	if (PyInt_Check(res)) {
-		Py_ssize_t temp = PyInt_AsSsize_t(res);
-		if (temp == -1 && PyErr_Occurred()) {
+		outcome = PyInt_AsSsize_t(res);
+		if (outcome == -1 && PyErr_Occurred()) {
 			Py_DECREF(res);
 			return -1;
 		}
-		outcome = (Py_ssize_t)temp;
-#if SIZEOF_SIZE_T < SIZEOF_LONG
+#if SIZEOF_SIZE_T < SIZEOF_INT
 		/* Overflow check -- range of PyInt is more than C int */
-		if (outcome != temp) {
+		if (outcome != (int)outcome) {
 			PyErr_SetString(PyExc_OverflowError,
 			 "__len__() should return 0 <= outcome < 2**31");
 			outcome = -1;
 		}
 		else
 #endif
-		if (outcome < 0)
+		if (outcome < 0) {
 			PyErr_SetString(PyExc_ValueError,
 					"__len__() should return >= 0");
+			outcome = -1;
+		}
 	}
 	else {
 		PyErr_SetString(PyExc_TypeError,
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 517d4db..6edd455 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4110,19 +4110,17 @@ slot_sq_length(PyObject *self)
 {
 	static PyObject *len_str;
 	PyObject *res = call_method(self, "__len__", &len_str, "()");
-	Py_ssize_t temp;
 	Py_ssize_t len;
 
 	if (res == NULL)
 		return -1;
-	temp = PyInt_AsSsize_t(res);
-	len = (int)temp;
+	len = PyInt_AsSsize_t(res);
 	Py_DECREF(res);
 	if (len == -1 && PyErr_Occurred())
 		return -1;
-#if SIZEOF_SIZE_T < SIZEOF_LONG
+#if SIZEOF_SIZE_T < SIZEOF_INT
 	/* Overflow check -- range of PyInt is more than C ssize_t */
-	if (len != temp) {
+	if (len != (int)len) {
 		PyErr_SetString(PyExc_OverflowError,
 			"__len__() should return 0 <= outcome < 2**31");
 		return -1;
-- 
cgit v0.12