summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2003-08-29 23:09:58 (GMT)
committerRaymond Hettinger <python@rcn.com>2003-08-29 23:09:58 (GMT)
commita56f6b6600ea8906562cfaa31859b72a53a8c0d7 (patch)
tree5379c5da992031907cc63202247dd8fa185cb9df
parentb738041c5db7a04b71ed4c3c8128dabc935ad60b (diff)
downloadcpython-a56f6b6600ea8906562cfaa31859b72a53a8c0d7.zip
cpython-a56f6b6600ea8906562cfaa31859b72a53a8c0d7.tar.gz
cpython-a56f6b6600ea8906562cfaa31859b72a53a8c0d7.tar.bz2
SF bug #793826: using itertools.izip to mutate tuples
Avoid Armin Rigo's dastardly exercise in re-entrancy.
-rw-r--r--Lib/test/test_itertools.py33
-rw-r--r--Modules/itertoolsmodule.c6
2 files changed, 36 insertions, 3 deletions
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index f96ccd5..057b576 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -427,6 +427,36 @@ class TestVariousIteratorArgs(unittest.TestCase):
self.assertRaises(TypeError, list, dropwhile(isOdd, N(s)))
self.assertRaises(ZeroDivisionError, list, dropwhile(isOdd, E(s)))
+class RegressionTests(unittest.TestCase):
+
+ def test_sf_793826(self):
+ # Fix Armin Rigo's successful efforts to wreak havoc
+
+ def mutatingtuple(tuple1, f, tuple2):
+ # this builds a tuple t which is a copy of tuple1,
+ # then calls f(t), then mutates t to be equal to tuple2
+ # (needs len(tuple1) == len(tuple2)).
+ def g(value, first=[1]):
+ if first:
+ del first[:]
+ f(z.next())
+ return value
+ items = list(tuple2)
+ items[1:1] = list(tuple1)
+ gen = imap(g, items)
+ z = izip(*[gen]*len(tuple1))
+ z.next()
+
+ def f(t):
+ global T
+ T = t
+ first[:] = list(T)
+
+ first = []
+ mutatingtuple((1,2,3), f, (4,5,6))
+ second = list(T)
+ self.assertEqual(first, second)
+
libreftest = """ Doctest for examples in the library reference: libitertools.tex
@@ -568,7 +598,8 @@ False
__test__ = {'libreftest' : libreftest}
def test_main(verbose=None):
- test_classes = (TestBasicOps, TestVariousIteratorArgs, TestGC)
+ test_classes = (TestBasicOps, TestVariousIteratorArgs, TestGC,
+ RegressionTests)
test_support.run_unittest(*test_classes)
# verify reference counting
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index 4a99fce..4dca054 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -1595,16 +1595,18 @@ izip_next(izipobject *lz)
if (tuplesize == 0)
return NULL;
if (result->ob_refcnt == 1) {
+ Py_INCREF(result);
for (i=0 ; i < tuplesize ; i++) {
it = PyTuple_GET_ITEM(lz->ittuple, i);
assert(PyIter_Check(it));
item = (*it->ob_type->tp_iternext)(it);
- if (item == NULL)
+ if (item == NULL) {
+ Py_DECREF(result);
return NULL;
+ }
Py_DECREF(PyTuple_GET_ITEM(result, i));
PyTuple_SET_ITEM(result, i, item);
}
- Py_INCREF(result);
} else {
result = PyTuple_New(tuplesize);
if (result == NULL)