Skip to content

Commit c9de882

Browse files
committed
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.
1 parent 2592e57 commit c9de882

4 files changed

Lines changed: 25 additions & 13 deletions

File tree

Lib/test/test_index.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ def test_large_longs(self):
181181
self.assertEqual(self.pos.__index__(), self.pos)
182182
self.assertEqual(self.neg.__index__(), self.neg)
183183

184-
def test_getitem(self):
185-
class GetItem(object):
184+
def _getitem_helper(self, base):
185+
class GetItem(base):
186186
def __len__(self):
187187
return maxint
188188
def __getitem__(self, key):
@@ -195,6 +195,13 @@ def __getslice__(self, i, j):
195195
self.assertEqual(x[self.neg:self.pos], (-1, maxint))
196196
self.assertEqual(x[self.neg:self.pos:1].indices(maxint), (0, maxint, 1))
197197

198+
def test_getitem(self):
199+
self._getitem_helper(object)
200+
201+
def test_getitem_classic(self):
202+
class Empty: pass
203+
self._getitem_helper(Empty)
204+
198205
def test_sequence_repeat(self):
199206
self.failUnlessRaises(OverflowError, lambda: "a" * self.pos)
200207
self.failUnlessRaises(OverflowError, lambda: "a" * self.neg)

Misc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ What's New in Python 2.5 release candidate 1?
1212
Core and builtins
1313
-----------------
1414

15+
- Fix bug related to __len__ functions using values > 2**32 on 64-bit machines
16+
with new-style classes.
17+
18+
- Fix bug related to __len__ functions returning negative values with
19+
classic classes.
20+
1521
- Patch #1538606, Fix __index__() clipping. There were some problems
1622
discovered with the API and how integers that didn't fit into Py_ssize_t
1723
were handled. This patch attempts to provide enough alternatives

Objects/classobject.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -974,24 +974,25 @@ instance_length(PyInstanceObject *inst)
974974
if (res == NULL)
975975
return -1;
976976
if (PyInt_Check(res)) {
977-
Py_ssize_t temp = PyInt_AsSsize_t(res);
978-
if (temp == -1 && PyErr_Occurred()) {
977+
outcome = PyInt_AsSsize_t(res);
978+
if (outcome == -1 && PyErr_Occurred()) {
979979
Py_DECREF(res);
980980
return -1;
981981
}
982-
outcome = (Py_ssize_t)temp;
983-
#if SIZEOF_SIZE_T < SIZEOF_LONG
982+
#if SIZEOF_SIZE_T < SIZEOF_INT
984983
/* Overflow check -- range of PyInt is more than C int */
985-
if (outcome != temp) {
984+
if (outcome != (int)outcome) {
986985
PyErr_SetString(PyExc_OverflowError,
987986
"__len__() should return 0 <= outcome < 2**31");
988987
outcome = -1;
989988
}
990989
else
991990
#endif
992-
if (outcome < 0)
991+
if (outcome < 0) {
993992
PyErr_SetString(PyExc_ValueError,
994993
"__len__() should return >= 0");
994+
outcome = -1;
995+
}
995996
}
996997
else {
997998
PyErr_SetString(PyExc_TypeError,

Objects/typeobject.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4110,19 +4110,17 @@ slot_sq_length(PyObject *self)
41104110
{
41114111
static PyObject *len_str;
41124112
PyObject *res = call_method(self, "__len__", &len_str, "()");
4113-
Py_ssize_t temp;
41144113
Py_ssize_t len;
41154114

41164115
if (res == NULL)
41174116
return -1;
4118-
temp = PyInt_AsSsize_t(res);
4119-
len = (int)temp;
4117+
len = PyInt_AsSsize_t(res);
41204118
Py_DECREF(res);
41214119
if (len == -1 && PyErr_Occurred())
41224120
return -1;
4123-
#if SIZEOF_SIZE_T < SIZEOF_LONG
4121+
#if SIZEOF_SIZE_T < SIZEOF_INT
41244122
/* Overflow check -- range of PyInt is more than C ssize_t */
4125-
if (len != temp) {
4123+
if (len != (int)len) {
41264124
PyErr_SetString(PyExc_OverflowError,
41274125
"__len__() should return 0 <= outcome < 2**31");
41284126
return -1;

0 commit comments

Comments
 (0)