[Python-checkins] r68560 - in python/trunk: Include/abstract.h Include/object.h Lib/test/crashers/iter.py Lib/test/test_iter.py Misc/NEWS Modules/itertoolsmodule.c Objects/abstract.c Objects/object.c Objects/typeobject.c
amaury.forgeotdarc
python-checkins at python.org
Tue Jan 13 00:36:55 CET 2009
Author: amaury.forgeotdarc
Date: Tue Jan 13 00:36:55 2009
New Revision: 68560
Log:
#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.
Removed:
python/trunk/Lib/test/crashers/iter.py
Modified:
python/trunk/Include/abstract.h
python/trunk/Include/object.h
python/trunk/Lib/test/test_iter.py
python/trunk/Misc/NEWS
python/trunk/Modules/itertoolsmodule.c
python/trunk/Objects/abstract.c
python/trunk/Objects/object.c
python/trunk/Objects/typeobject.c
Modified: python/trunk/Include/abstract.h
==============================================================================
--- python/trunk/Include/abstract.h (original)
+++ python/trunk/Include/abstract.h Tue Jan 13 00:36:55 2009
@@ -636,7 +636,8 @@
#define PyIter_Check(obj) \
(PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \
- (obj)->ob_type->tp_iternext != NULL)
+ (obj)->ob_type->tp_iternext != NULL && \
+ (obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented)
PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *);
/* Takes an iterator object and calls its tp_iternext slot,
Modified: python/trunk/Include/object.h
==============================================================================
--- python/trunk/Include/object.h (original)
+++ python/trunk/Include/object.h Tue Jan 13 00:36:55 2009
@@ -473,6 +473,7 @@
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *);
+PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *);
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
PyObject *, PyObject *);
Deleted: python/trunk/Lib/test/crashers/iter.py
==============================================================================
--- python/trunk/Lib/test/crashers/iter.py Tue Jan 13 00:36:55 2009
+++ (empty file)
@@ -1,53 +0,0 @@
-# Calls to PyIter_Next, or direct calls to tp_iternext, on an object
-# which might no longer be an iterable because its 'next' method was
-# removed. These are all variants of Issue3720.
-
-"""
-Run this script with an argument between 1 and <N> to test for
-different crashes.
-"""
-N = 8
-
-import sys
-
-class Foo(object):
- def __iter__(self):
- return self
- def next(self):
- del Foo.next
- return (1, 2)
-
-def case1():
- list(enumerate(Foo()))
-
-def case2():
- x, y = Foo()
-
-def case3():
- filter(None, Foo())
-
-def case4():
- map(None, Foo(), Foo())
-
-def case5():
- max(Foo())
-
-def case6():
- sum(Foo(), ())
-
-def case7():
- dict(Foo())
-
-def case8():
- sys.stdout.writelines(Foo())
-
-# etc...
-
-
-if __name__ == '__main__':
- if len(sys.argv) < 2:
- print __doc__.replace('<N>', str(N))
- else:
- n = int(sys.argv[1])
- func = globals()['case%d' % n]
- func()
Modified: python/trunk/Lib/test/test_iter.py
==============================================================================
--- python/trunk/Lib/test/test_iter.py (original)
+++ python/trunk/Lib/test/test_iter.py Tue Jan 13 00:36:55 2009
@@ -120,6 +120,13 @@
def test_seq_class_iter(self):
self.check_iterator(iter(SequenceClass(10)), range(10))
+ # Test a new_style class with __iter__ but no next() method
+ def test_new_style_iter_class(self):
+ class IterClass(object):
+ def __iter__(self):
+ return self
+ self.assertRaises(TypeError, iter, IterClass())
+
# Test two-argument iter() with callable instance
def test_iter_callable(self):
class C:
@@ -877,6 +884,21 @@
self.assertEqual(list(b), zip(range(5), range(5)))
self.assertEqual(list(b), [])
+ def test_3720(self):
+ # Avoid a crash, when an iterator deletes its next() method.
+ class BadIterator(object):
+ def __iter__(self):
+ return self
+ def next(self):
+ del BadIterator.next
+ return 1
+
+ try:
+ for i in BadIterator() :
+ pass
+ except TypeError:
+ pass
+
def test_main():
run_unittest(TestCase)
Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS (original)
+++ python/trunk/Misc/NEWS Tue Jan 13 00:36:55 2009
@@ -12,6 +12,9 @@
Core and Builtins
-----------------
+- Issue #3720: Fix a crash when an iterator modifies its class and removes its
+ __next__ method.
+
- Issue #4893: Use NT threading on CE.
- Issue #4915: Port sysmodule to Windows CE.
Modified: python/trunk/Modules/itertoolsmodule.c
==============================================================================
--- python/trunk/Modules/itertoolsmodule.c (original)
+++ python/trunk/Modules/itertoolsmodule.c Tue Jan 13 00:36:55 2009
@@ -886,7 +886,6 @@
long ok;
PyObject *(*iternext)(PyObject *);
- assert(PyIter_Check(it));
iternext = *Py_TYPE(it)->tp_iternext;
for (;;) {
item = iternext(it);
@@ -1031,7 +1030,6 @@
if (lz->stop == 1)
return NULL;
- assert(PyIter_Check(it));
item = (*Py_TYPE(it)->tp_iternext)(it);
if (item == NULL)
return NULL;
@@ -1218,7 +1216,6 @@
Py_ssize_t oldnext;
PyObject *(*iternext)(PyObject *);
- assert(PyIter_Check(it));
iternext = *Py_TYPE(it)->tp_iternext;
while (lz->cnt < lz->next) {
item = iternext(it);
@@ -1229,7 +1226,6 @@
}
if (lz->stop != -1 && lz->cnt >= lz->stop)
return NULL;
- assert(PyIter_Check(it));
item = iternext(it);
if (item == NULL)
return NULL;
@@ -1361,7 +1357,6 @@
PyObject *result;
PyObject *it = lz->it;
- assert(PyIter_Check(it));
args = (*Py_TYPE(it)->tp_iternext)(it);
if (args == NULL)
return NULL;
@@ -2577,7 +2572,6 @@
long ok;
PyObject *(*iternext)(PyObject *);
- assert(PyIter_Check(it));
iternext = *Py_TYPE(it)->tp_iternext;
for (;;) {
item = iternext(it);
@@ -2721,7 +2715,6 @@
long ok;
PyObject *(*iternext)(PyObject *);
- assert(PyIter_Check(it));
iternext = *Py_TYPE(it)->tp_iternext;
for (;;) {
item = iternext(it);
@@ -3059,7 +3052,6 @@
Py_INCREF(result);
for (i=0 ; i < tuplesize ; i++) {
it = PyTuple_GET_ITEM(lz->ittuple, i);
- assert(PyIter_Check(it));
item = (*Py_TYPE(it)->tp_iternext)(it);
if (item == NULL) {
Py_DECREF(result);
@@ -3075,7 +3067,6 @@
return NULL;
for (i=0 ; i < tuplesize ; i++) {
it = PyTuple_GET_ITEM(lz->ittuple, i);
- assert(PyIter_Check(it));
item = (*Py_TYPE(it)->tp_iternext)(it);
if (item == NULL) {
Py_DECREF(result);
@@ -3411,7 +3402,6 @@
Py_INCREF(lz->fillvalue);
item = lz->fillvalue;
} else {
- assert(PyIter_Check(it));
item = (*Py_TYPE(it)->tp_iternext)(it);
if (item == NULL) {
lz->numactive -= 1;
@@ -3440,7 +3430,6 @@
Py_INCREF(lz->fillvalue);
item = lz->fillvalue;
} else {
- assert(PyIter_Check(it));
item = (*Py_TYPE(it)->tp_iternext)(it);
if (item == NULL) {
lz->numactive -= 1;
Modified: python/trunk/Objects/abstract.c
==============================================================================
--- python/trunk/Objects/abstract.c (original)
+++ python/trunk/Objects/abstract.c Tue Jan 13 00:36:55 2009
@@ -3067,7 +3067,6 @@
PyIter_Next(PyObject *iter)
{
PyObject *result;
- assert(PyIter_Check(iter));
result = (*iter->ob_type->tp_iternext)(iter);
if (result == NULL &&
PyErr_Occurred() &&
Modified: python/trunk/Objects/object.c
==============================================================================
--- python/trunk/Objects/object.c (original)
+++ python/trunk/Objects/object.c Tue Jan 13 00:36:55 2009
@@ -1305,6 +1305,20 @@
return obj;
}
+/* Helper used when the __next__ method is removed from a type:
+ tp_iternext is never NULL and can be safely called without checking
+ on every iteration.
+ */
+
+PyObject *
+_PyObject_NextNotImplemented(PyObject *self)
+{
+ PyErr_Format(PyExc_TypeError,
+ "'%.200s' object is not iterable",
+ Py_TYPE(self)->tp_name);
+ return NULL;
+}
+
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */
PyObject *
Modified: python/trunk/Objects/typeobject.c
==============================================================================
--- python/trunk/Objects/typeobject.c (original)
+++ python/trunk/Objects/typeobject.c Tue Jan 13 00:36:55 2009
@@ -6090,8 +6090,12 @@
}
do {
descr = _PyType_Lookup(type, p->name_strobj);
- if (descr == NULL)
+ if (descr == NULL) {
+ if (ptr == (void**)&type->tp_iternext) {
+ specific = _PyObject_NextNotImplemented;
+ }
continue;
+ }
if (Py_TYPE(descr) == &PyWrapperDescr_Type) {
void **tptr = resolve_slotdups(type, p->name_strobj);
if (tptr == NULL || tptr == ptr)
More information about the Python-checkins
mailing list