Skip to content

Commit b76ae2a

Browse files
author
amaury.forgeotdarc
committed
#3720: Interpreter crashes when an evil iterator removes its own next function.
Now the slot is filled with a function that always raises. Will not backport: extensions compiled with 2.6.x would not run on 2.6.0. git-svn-id: http://svn.python.org/projects/python/trunk@68560 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 083efea commit b76ae2a

9 files changed

Lines changed: 47 additions & 67 deletions

File tree

Include/abstract.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
636636

637637
#define PyIter_Check(obj) \
638638
(PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \
639-
(obj)->ob_type->tp_iternext != NULL)
639+
(obj)->ob_type->tp_iternext != NULL && \
640+
(obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented)
640641

641642
PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *);
642643
/* Takes an iterator object and calls its tp_iternext slot,

Include/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
473473
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
474474
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
475475
PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *);
476+
PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *);
476477
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
477478
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
478479
PyObject *, PyObject *);

Lib/test/crashers/iter.py

Lines changed: 0 additions & 53 deletions
This file was deleted.

Lib/test/test_iter.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ def test_seq_class_for(self):
120120
def test_seq_class_iter(self):
121121
self.check_iterator(iter(SequenceClass(10)), range(10))
122122

123+
# Test a new_style class with __iter__ but no next() method
124+
def test_new_style_iter_class(self):
125+
class IterClass(object):
126+
def __iter__(self):
127+
return self
128+
self.assertRaises(TypeError, iter, IterClass())
129+
123130
# Test two-argument iter() with callable instance
124131
def test_iter_callable(self):
125132
class C:
@@ -877,6 +884,21 @@ def test_sinkstate_enumerate(self):
877884
self.assertEqual(list(b), zip(range(5), range(5)))
878885
self.assertEqual(list(b), [])
879886

887+
def test_3720(self):
888+
# Avoid a crash, when an iterator deletes its next() method.
889+
class BadIterator(object):
890+
def __iter__(self):
891+
return self
892+
def next(self):
893+
del BadIterator.next
894+
return 1
895+
896+
try:
897+
for i in BadIterator() :
898+
pass
899+
except TypeError:
900+
pass
901+
880902

881903
def test_main():
882904
run_unittest(TestCase)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 1
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #3720: Fix a crash when an iterator modifies its class and removes its
16+
__next__ method.
17+
1518
- Issue #4893: Use NT threading on CE.
1619

1720
- Issue #4915: Port sysmodule to Windows CE.

Modules/itertoolsmodule.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,6 @@ dropwhile_next(dropwhileobject *lz)
886886
long ok;
887887
PyObject *(*iternext)(PyObject *);
888888

889-
assert(PyIter_Check(it));
890889
iternext = *Py_TYPE(it)->tp_iternext;
891890
for (;;) {
892891
item = iternext(it);
@@ -1031,7 +1030,6 @@ takewhile_next(takewhileobject *lz)
10311030
if (lz->stop == 1)
10321031
return NULL;
10331032

1034-
assert(PyIter_Check(it));
10351033
item = (*Py_TYPE(it)->tp_iternext)(it);
10361034
if (item == NULL)
10371035
return NULL;
@@ -1218,7 +1216,6 @@ islice_next(isliceobject *lz)
12181216
Py_ssize_t oldnext;
12191217
PyObject *(*iternext)(PyObject *);
12201218

1221-
assert(PyIter_Check(it));
12221219
iternext = *Py_TYPE(it)->tp_iternext;
12231220
while (lz->cnt < lz->next) {
12241221
item = iternext(it);
@@ -1229,7 +1226,6 @@ islice_next(isliceobject *lz)
12291226
}
12301227
if (lz->stop != -1 && lz->cnt >= lz->stop)
12311228
return NULL;
1232-
assert(PyIter_Check(it));
12331229
item = iternext(it);
12341230
if (item == NULL)
12351231
return NULL;
@@ -1361,7 +1357,6 @@ starmap_next(starmapobject *lz)
13611357
PyObject *result;
13621358
PyObject *it = lz->it;
13631359

1364-
assert(PyIter_Check(it));
13651360
args = (*Py_TYPE(it)->tp_iternext)(it);
13661361
if (args == NULL)
13671362
return NULL;
@@ -2577,7 +2572,6 @@ ifilter_next(ifilterobject *lz)
25772572
long ok;
25782573
PyObject *(*iternext)(PyObject *);
25792574

2580-
assert(PyIter_Check(it));
25812575
iternext = *Py_TYPE(it)->tp_iternext;
25822576
for (;;) {
25832577
item = iternext(it);
@@ -2721,7 +2715,6 @@ ifilterfalse_next(ifilterfalseobject *lz)
27212715
long ok;
27222716
PyObject *(*iternext)(PyObject *);
27232717

2724-
assert(PyIter_Check(it));
27252718
iternext = *Py_TYPE(it)->tp_iternext;
27262719
for (;;) {
27272720
item = iternext(it);
@@ -3059,7 +3052,6 @@ izip_next(izipobject *lz)
30593052
Py_INCREF(result);
30603053
for (i=0 ; i < tuplesize ; i++) {
30613054
it = PyTuple_GET_ITEM(lz->ittuple, i);
3062-
assert(PyIter_Check(it));
30633055
item = (*Py_TYPE(it)->tp_iternext)(it);
30643056
if (item == NULL) {
30653057
Py_DECREF(result);
@@ -3075,7 +3067,6 @@ izip_next(izipobject *lz)
30753067
return NULL;
30763068
for (i=0 ; i < tuplesize ; i++) {
30773069
it = PyTuple_GET_ITEM(lz->ittuple, i);
3078-
assert(PyIter_Check(it));
30793070
item = (*Py_TYPE(it)->tp_iternext)(it);
30803071
if (item == NULL) {
30813072
Py_DECREF(result);
@@ -3411,7 +3402,6 @@ izip_longest_next(iziplongestobject *lz)
34113402
Py_INCREF(lz->fillvalue);
34123403
item = lz->fillvalue;
34133404
} else {
3414-
assert(PyIter_Check(it));
34153405
item = (*Py_TYPE(it)->tp_iternext)(it);
34163406
if (item == NULL) {
34173407
lz->numactive -= 1;
@@ -3440,7 +3430,6 @@ izip_longest_next(iziplongestobject *lz)
34403430
Py_INCREF(lz->fillvalue);
34413431
item = lz->fillvalue;
34423432
} else {
3443-
assert(PyIter_Check(it));
34443433
item = (*Py_TYPE(it)->tp_iternext)(it);
34453434
if (item == NULL) {
34463435
lz->numactive -= 1;

Objects/abstract.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3067,7 +3067,6 @@ PyObject *
30673067
PyIter_Next(PyObject *iter)
30683068
{
30693069
PyObject *result;
3070-
assert(PyIter_Check(iter));
30713070
result = (*iter->ob_type->tp_iternext)(iter);
30723071
if (result == NULL &&
30733072
PyErr_Occurred() &&

Objects/object.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,20 @@ PyObject_SelfIter(PyObject *obj)
13051305
return obj;
13061306
}
13071307

1308+
/* Helper used when the __next__ method is removed from a type:
1309+
tp_iternext is never NULL and can be safely called without checking
1310+
on every iteration.
1311+
*/
1312+
1313+
PyObject *
1314+
_PyObject_NextNotImplemented(PyObject *self)
1315+
{
1316+
PyErr_Format(PyExc_TypeError,
1317+
"'%.200s' object is not iterable",
1318+
Py_TYPE(self)->tp_name);
1319+
return NULL;
1320+
}
1321+
13081322
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */
13091323

13101324
PyObject *

Objects/typeobject.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6090,8 +6090,12 @@ update_one_slot(PyTypeObject *type, slotdef *p)
60906090
}
60916091
do {
60926092
descr = _PyType_Lookup(type, p->name_strobj);
6093-
if (descr == NULL)
6093+
if (descr == NULL) {
6094+
if (ptr == (void**)&type->tp_iternext) {
6095+
specific = _PyObject_NextNotImplemented;
6096+
}
60946097
continue;
6098+
}
60956099
if (Py_TYPE(descr) == &PyWrapperDescr_Type) {
60966100
void **tptr = resolve_slotdups(type, p->name_strobj);
60976101
if (tptr == NULL || tptr == ptr)

0 commit comments

Comments
 (0)