mirror of
https://github.com/python/cpython.git
synced 2025-07-23 19:25:40 +00:00
Merged revisions 68560 via svnmerge from
svn+ssh://pythondev@svn.python.org/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. ........
This commit is contained in:
parent
e5e298f875
commit
f343e01c17
10 changed files with 47 additions and 67 deletions
|
@ -612,7 +612,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
|
||||||
is an iterator, this returns itself. */
|
is an iterator, this returns itself. */
|
||||||
|
|
||||||
#define PyIter_Check(obj) \
|
#define PyIter_Check(obj) \
|
||||||
((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 *);
|
PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *);
|
||||||
/* Takes an iterator object and calls its tp_iternext slot,
|
/* Takes an iterator object and calls its tp_iternext slot,
|
||||||
|
|
|
@ -438,6 +438,7 @@ PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
|
||||||
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
|
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
|
||||||
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
|
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
|
||||||
PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *);
|
PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *);
|
||||||
|
PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *);
|
||||||
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
|
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
|
||||||
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
|
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
|
||||||
PyObject *, PyObject *);
|
PyObject *, PyObject *);
|
||||||
|
|
|
@ -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()
|
|
|
@ -120,6 +120,13 @@ class TestCase(unittest.TestCase):
|
||||||
def test_seq_class_iter(self):
|
def test_seq_class_iter(self):
|
||||||
self.check_iterator(iter(SequenceClass(10)), list(range(10)))
|
self.check_iterator(iter(SequenceClass(10)), list(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
|
# Test two-argument iter() with callable instance
|
||||||
def test_iter_callable(self):
|
def test_iter_callable(self):
|
||||||
class C:
|
class C:
|
||||||
|
@ -853,6 +860,21 @@ class TestCase(unittest.TestCase):
|
||||||
self.assertEqual(list(b), list(zip(range(5), range(5))))
|
self.assertEqual(list(b), list(zip(range(5), range(5))))
|
||||||
self.assertEqual(list(b), [])
|
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():
|
def test_main():
|
||||||
run_unittest(TestCase)
|
run_unittest(TestCase)
|
||||||
|
|
|
@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #3720: Fix a crash when an iterator modifies its class and removes its
|
||||||
|
__next__ method.
|
||||||
|
|
||||||
- Issue #4910: Builtin int() function and PyNumber_Long/PyNumber_Int API
|
- Issue #4910: Builtin int() function and PyNumber_Long/PyNumber_Int API
|
||||||
function no longer attempt to call the __long__ slot to convert an object
|
function no longer attempt to call the __long__ slot to convert an object
|
||||||
to an integer. Only the __int__ and __trunc__ slots are examined.
|
to an integer. Only the __int__ and __trunc__ slots are examined.
|
||||||
|
|
|
@ -886,7 +886,6 @@ dropwhile_next(dropwhileobject *lz)
|
||||||
long ok;
|
long ok;
|
||||||
PyObject *(*iternext)(PyObject *);
|
PyObject *(*iternext)(PyObject *);
|
||||||
|
|
||||||
assert(PyIter_Check(it));
|
|
||||||
iternext = *Py_TYPE(it)->tp_iternext;
|
iternext = *Py_TYPE(it)->tp_iternext;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
item = iternext(it);
|
item = iternext(it);
|
||||||
|
@ -1031,7 +1030,6 @@ takewhile_next(takewhileobject *lz)
|
||||||
if (lz->stop == 1)
|
if (lz->stop == 1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
assert(PyIter_Check(it));
|
|
||||||
item = (*Py_TYPE(it)->tp_iternext)(it);
|
item = (*Py_TYPE(it)->tp_iternext)(it);
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1218,7 +1216,6 @@ islice_next(isliceobject *lz)
|
||||||
Py_ssize_t oldnext;
|
Py_ssize_t oldnext;
|
||||||
PyObject *(*iternext)(PyObject *);
|
PyObject *(*iternext)(PyObject *);
|
||||||
|
|
||||||
assert(PyIter_Check(it));
|
|
||||||
iternext = *Py_TYPE(it)->tp_iternext;
|
iternext = *Py_TYPE(it)->tp_iternext;
|
||||||
while (lz->cnt < lz->next) {
|
while (lz->cnt < lz->next) {
|
||||||
item = iternext(it);
|
item = iternext(it);
|
||||||
|
@ -1229,7 +1226,6 @@ islice_next(isliceobject *lz)
|
||||||
}
|
}
|
||||||
if (lz->stop != -1 && lz->cnt >= lz->stop)
|
if (lz->stop != -1 && lz->cnt >= lz->stop)
|
||||||
return NULL;
|
return NULL;
|
||||||
assert(PyIter_Check(it));
|
|
||||||
item = iternext(it);
|
item = iternext(it);
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1361,7 +1357,6 @@ starmap_next(starmapobject *lz)
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
PyObject *it = lz->it;
|
PyObject *it = lz->it;
|
||||||
|
|
||||||
assert(PyIter_Check(it));
|
|
||||||
args = (*Py_TYPE(it)->tp_iternext)(it);
|
args = (*Py_TYPE(it)->tp_iternext)(it);
|
||||||
if (args == NULL)
|
if (args == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2403,7 +2398,6 @@ filterfalse_next(filterfalseobject *lz)
|
||||||
long ok;
|
long ok;
|
||||||
PyObject *(*iternext)(PyObject *);
|
PyObject *(*iternext)(PyObject *);
|
||||||
|
|
||||||
assert(PyIter_Check(it));
|
|
||||||
iternext = *Py_TYPE(it)->tp_iternext;
|
iternext = *Py_TYPE(it)->tp_iternext;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
item = iternext(it);
|
item = iternext(it);
|
||||||
|
@ -2888,7 +2882,6 @@ zip_longest_next(ziplongestobject *lz)
|
||||||
Py_INCREF(lz->fillvalue);
|
Py_INCREF(lz->fillvalue);
|
||||||
item = lz->fillvalue;
|
item = lz->fillvalue;
|
||||||
} else {
|
} else {
|
||||||
assert(PyIter_Check(it));
|
|
||||||
item = (*Py_TYPE(it)->tp_iternext)(it);
|
item = (*Py_TYPE(it)->tp_iternext)(it);
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
lz->numactive -= 1;
|
lz->numactive -= 1;
|
||||||
|
@ -2917,7 +2910,6 @@ zip_longest_next(ziplongestobject *lz)
|
||||||
Py_INCREF(lz->fillvalue);
|
Py_INCREF(lz->fillvalue);
|
||||||
item = lz->fillvalue;
|
item = lz->fillvalue;
|
||||||
} else {
|
} else {
|
||||||
assert(PyIter_Check(it));
|
|
||||||
item = (*Py_TYPE(it)->tp_iternext)(it);
|
item = (*Py_TYPE(it)->tp_iternext)(it);
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
lz->numactive -= 1;
|
lz->numactive -= 1;
|
||||||
|
|
|
@ -2736,7 +2736,6 @@ PyObject *
|
||||||
PyIter_Next(PyObject *iter)
|
PyIter_Next(PyObject *iter)
|
||||||
{
|
{
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
assert(PyIter_Check(iter));
|
|
||||||
result = (*iter->ob_type->tp_iternext)(iter);
|
result = (*iter->ob_type->tp_iternext)(iter);
|
||||||
if (result == NULL &&
|
if (result == NULL &&
|
||||||
PyErr_Occurred() &&
|
PyErr_Occurred() &&
|
||||||
|
|
|
@ -1020,6 +1020,20 @@ PyObject_SelfIter(PyObject *obj)
|
||||||
return obj;
|
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 */
|
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
|
|
@ -5630,8 +5630,12 @@ update_one_slot(PyTypeObject *type, slotdef *p)
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
descr = _PyType_Lookup(type, p->name_strobj);
|
descr = _PyType_Lookup(type, p->name_strobj);
|
||||||
if (descr == NULL)
|
if (descr == NULL) {
|
||||||
|
if (ptr == (void**)&type->tp_iternext) {
|
||||||
|
specific = _PyObject_NextNotImplemented;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (Py_TYPE(descr) == &PyWrapperDescr_Type) {
|
if (Py_TYPE(descr) == &PyWrapperDescr_Type) {
|
||||||
void **tptr = resolve_slotdups(type, p->name_strobj);
|
void **tptr = resolve_slotdups(type, p->name_strobj);
|
||||||
if (tptr == NULL || tptr == ptr)
|
if (tptr == NULL || tptr == ptr)
|
||||||
|
|
|
@ -375,7 +375,6 @@ filter_next(filterobject *lz)
|
||||||
long ok;
|
long ok;
|
||||||
PyObject *(*iternext)(PyObject *);
|
PyObject *(*iternext)(PyObject *);
|
||||||
|
|
||||||
assert(PyIter_Check(it));
|
|
||||||
iternext = *Py_TYPE(it)->tp_iternext;
|
iternext = *Py_TYPE(it)->tp_iternext;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
item = iternext(it);
|
item = iternext(it);
|
||||||
|
@ -2144,7 +2143,6 @@ zip_next(zipobject *lz)
|
||||||
Py_INCREF(result);
|
Py_INCREF(result);
|
||||||
for (i=0 ; i < tuplesize ; i++) {
|
for (i=0 ; i < tuplesize ; i++) {
|
||||||
it = PyTuple_GET_ITEM(lz->ittuple, i);
|
it = PyTuple_GET_ITEM(lz->ittuple, i);
|
||||||
assert(PyIter_Check(it));
|
|
||||||
item = (*Py_TYPE(it)->tp_iternext)(it);
|
item = (*Py_TYPE(it)->tp_iternext)(it);
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
|
@ -2160,7 +2158,6 @@ zip_next(zipobject *lz)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (i=0 ; i < tuplesize ; i++) {
|
for (i=0 ; i < tuplesize ; i++) {
|
||||||
it = PyTuple_GET_ITEM(lz->ittuple, i);
|
it = PyTuple_GET_ITEM(lz->ittuple, i);
|
||||||
assert(PyIter_Check(it));
|
|
||||||
item = (*Py_TYPE(it)->tp_iternext)(it);
|
item = (*Py_TYPE(it)->tp_iternext)(it);
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue