Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f343e01

Browse files
committed
Merged revisions 68560 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r68560 | amaury.forgeotdarc | 2009-01-13 00:36:55 +0100 (mar., 13 janv. 2009) | 6 lines #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. ........
1 parent e5e298f commit f343e01

10 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
@@ -612,7 +612,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
612612
is an iterator, this returns itself. */
613613

614614
#define PyIter_Check(obj) \
615-
((obj)->ob_type->tp_iternext != NULL)
615+
((obj)->ob_type->tp_iternext != NULL && \
616+
(obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented)
616617

617618
PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *);
618619
/* 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
@@ -438,6 +438,7 @@ PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
438438
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
439439
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
440440
PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *);
441+
PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *);
441442
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
442443
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
443444
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)), list(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:
@@ -853,6 +860,21 @@ def test_sinkstate_enumerate(self):
853860
self.assertEqual(list(b), list(zip(range(5), range(5))))
854861
self.assertEqual(list(b), [])
855862

863+
def test_3720(self):
864+
# Avoid a crash, when an iterator deletes its next() method.
865+
class BadIterator(object):
866+
def __iter__(self):
867+
return self
868+
def __next__(self):
869+
del BadIterator.__next__
870+
return 1
871+
872+
try:
873+
for i in BadIterator() :
874+
pass
875+
except TypeError:
876+
pass
877+
856878

857879
def test_main():
858880
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 3.1 alpha 0
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 #4910: Builtin int() function and PyNumber_Long/PyNumber_Int API
1619
function no longer attempt to call the __long__ slot to convert an object
1720
to an integer. Only the __int__ and __trunc__ slots are examined.

Modules/itertoolsmodule.c

Lines changed: 0 additions & 8 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;
@@ -2403,7 +2398,6 @@ filterfalse_next(filterfalseobject *lz)
24032398
long ok;
24042399
PyObject *(*iternext)(PyObject *);
24052400

2406-
assert(PyIter_Check(it));
24072401
iternext = *Py_TYPE(it)->tp_iternext;
24082402
for (;;) {
24092403
item = iternext(it);
@@ -2888,7 +2882,6 @@ zip_longest_next(ziplongestobject *lz)
28882882
Py_INCREF(lz->fillvalue);
28892883
item = lz->fillvalue;
28902884
} else {
2891-
assert(PyIter_Check(it));
28922885
item = (*Py_TYPE(it)->tp_iternext)(it);
28932886
if (item == NULL) {
28942887
lz->numactive -= 1;
@@ -2917,7 +2910,6 @@ zip_longest_next(ziplongestobject *lz)
29172910
Py_INCREF(lz->fillvalue);
29182911
item = lz->fillvalue;
29192912
} else {
2920-
assert(PyIter_Check(it));
29212913
item = (*Py_TYPE(it)->tp_iternext)(it);
29222914
if (item == NULL) {
29232915
lz->numactive -= 1;

Objects/abstract.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2736,7 +2736,6 @@ PyObject *
27362736
PyIter_Next(PyObject *iter)
27372737
{
27382738
PyObject *result;
2739-
assert(PyIter_Check(iter));
27402739
result = (*iter->ob_type->tp_iternext)(iter);
27412740
if (result == NULL &&
27422741
PyErr_Occurred() &&

Objects/object.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,20 @@ PyObject_SelfIter(PyObject *obj)
10201020
return obj;
10211021
}
10221022

1023+
/* Helper used when the __next__ method is removed from a type:
1024+
tp_iternext is never NULL and can be safely called without checking
1025+
on every iteration.
1026+
*/
1027+
1028+
PyObject *
1029+
_PyObject_NextNotImplemented(PyObject *self)
1030+
{
1031+
PyErr_Format(PyExc_TypeError,
1032+
"'%.200s' object is not iterable",
1033+
Py_TYPE(self)->tp_name);
1034+
return NULL;
1035+
}
1036+
10231037
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */
10241038

10251039
PyObject *

Objects/typeobject.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5630,8 +5630,12 @@ update_one_slot(PyTypeObject *type, slotdef *p)
56305630
}
56315631
do {
56325632
descr = _PyType_Lookup(type, p->name_strobj);
5633-
if (descr == NULL)
5633+
if (descr == NULL) {
5634+
if (ptr == (void**)&type->tp_iternext) {
5635+
specific = _PyObject_NextNotImplemented;
5636+
}
56345637
continue;
5638+
}
56355639
if (Py_TYPE(descr) == &PyWrapperDescr_Type) {
56365640
void **tptr = resolve_slotdups(type, p->name_strobj);
56375641
if (tptr == NULL || tptr == ptr)

Python/bltinmodule.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ filter_next(filterobject *lz)
375375
long ok;
376376
PyObject *(*iternext)(PyObject *);
377377

378-
assert(PyIter_Check(it));
379378
iternext = *Py_TYPE(it)->tp_iternext;
380379
for (;;) {
381380
item = iternext(it);
@@ -2144,7 +2143,6 @@ zip_next(zipobject *lz)
21442143
Py_INCREF(result);
21452144
for (i=0 ; i < tuplesize ; i++) {
21462145
it = PyTuple_GET_ITEM(lz->ittuple, i);
2147-
assert(PyIter_Check(it));
21482146
item = (*Py_TYPE(it)->tp_iternext)(it);
21492147
if (item == NULL) {
21502148
Py_DECREF(result);
@@ -2160,7 +2158,6 @@ zip_next(zipobject *lz)
21602158
return NULL;
21612159
for (i=0 ; i < tuplesize ; i++) {
21622160
it = PyTuple_GET_ITEM(lz->ittuple, i);
2163-
assert(PyIter_Check(it));
21642161
item = (*Py_TYPE(it)->tp_iternext)(it);
21652162
if (item == NULL) {
21662163
Py_DECREF(result);

0 commit comments

Comments
 (0)