[pypy-issue] [issue1100] Dict iterators can return deleted entries
Danilo Araujo de Freitas
tracker at bugs.pypy.org
Sun Apr 1 17:44:09 CEST 2012
Danilo Araujo de Freitas <dsurviver at gmail.com> added the comment:
I'm trying to fix it, but my patch is still not good enough:
--- a/pypy/objspace/std/dictmultiobject.py Thu Mar 29 11:31:34 2012 -0400
+++ b/pypy/objspace/std/dictmultiobject.py Sun Apr 01 12:31:37 2012 -0300
@@ -277,13 +277,13 @@
raise OperationError(self.space.w_RuntimeError,
self.space.wrap("dictionary changed size during
iteration"))
# look for the next entry
- if self.pos < self.len:
- result = self.next_entry()
- self.pos += 1
- return result
+ #if self.pos < self.len:
+ result = self.next_entry()
+ self.pos += 1
+ return result
# no more entries
- self.dictimplementation = None
- return None, None
+ #self.dictimplementation = None
+ #return None, None
def next_entry(self):
""" Purely abstract method
@@ -491,11 +491,20 @@
def __init__(self, space, strategy, dictimplementation):
IteratorImplementation.__init__(self, space, dictimplementation)
self.iterator =
strategy.unerase(dictimplementation.dstorage).iteritems()
+ self.strategy = strategy
def next_entry(self):
+ if self.strategy != self.dictimplementation.strategy:
+ self.strategy = self.dictimplementation.strategy
+ storage = self.strategy.unerase(self.dictimplementation.dstorage)
+ iterator = storage.iteritems()
+ self.iterator = iterator
# note that this 'for' loop only runs once, at most
for key, w_value in self.iterator:
- return self.space.wrap(key), w_value
+ try:
+ return self.space.wrap(key), w_value
+ except TypeError:
+ return key, w_value
else:
return None, None
diff -r 285ff15e1498 pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py Thu Mar 29 11:31:34 2012
-0400
+++ b/pypy/objspace/std/test/test_dictmultiobject.py Sun Apr 01 12:31:37 2012
-0300
@@ -1006,6 +1006,65 @@
assert items == zip([self.string, self.string2], [1000, 2000])
self.check_not_devolved()
+ def test_iter_dict_change(self):
+ d = {1: 2, 3: 4, 5: 6}
+ it = d.iteritems()
+ items = []
+ items.append(it.next())
+ items.append(it.next())
+ d['foo'] = 'bar'
+ del d[1]
+ items.append(it.next())
+ items.append(it.next())
+ assert set(items) == set([(1, 2), (3, 4), (5, 6), ('foo', 'bar')])
+
+ items = []
+ d = {1: 1, 2: 2, 3: 3}
+ it = d.iteritems()
+ items.append(it.next())
+ d[4] = 4
+ del d[1]
+ items.append(it.next())
+ items.append(it.next())
+ items.append(it.next())
+ assert set(items) == set([(1, 1), (2, 2), (3, 3), (4, 4)])
+
+ items = []
+ d = {1: 1, 2: 2, 3: 3}
+ it = d.iteritems()
+ d['foo'] = 'bar'
+ del d[2]
+ d['bar'] = 'foo'
+ del d[3]
+ items.append(it.next())
+ items.append(it.next())
+ items.append(it.next())
+ assert set(items) == set([(1, 1), ('bar', 'foo'), ('foo', 'bar')])
+
+ items = []
+ d = {'foo': 'bar', 'bar': 'foo'}
+ it = d.iteritems()
+ del d['foo']
+ d[1] = 2
+ items.append(it.next())
+ items.append(it.next())
+ assert set(items) == set([(1, 2), ('bar', 'foo')])
+
+ items = []
+ d = {1: 1, 2: 2, 3: 3, 4: 4}
+ it = d.iteritems()
+ d['foo'] = 'bar'
+ del d[2]
+ items.append(it.next())
+ items.append(it.next())
+ d['bar'] = 'foo'
+ del d[3]
+ items.append(it.next())
+ items.append(it.next())
+ items.append(it.next())
+ assert set(items) == set([(1, 1), (3, 3), (4, 4), ('bar', 'foo'),
('foo', 'bar')])
+
+
def test_devolve(self):
impl = self.impl
for x in xrange(100):
diff -r 285ff15e1498 pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py Thu Mar 29 11:31:34 2012 -0400
+++ b/pypy/rlib/objectmodel.py Sun Apr 01 12:31:37 2012 -0300
@@ -590,7 +590,7 @@
return self._dict.itervalues()
def iteritems(self):
- for dk, value in self._dict.items():
+ for dk, value in self._dict.iteritems():
yield dk.key, value
def clear(self):
----------
nosy: +daniloaf
status: unread -> chatting
________________________________________
PyPy bug tracker <tracker at bugs.pypy.org>
<https://bugs.pypy.org/issue1100>
________________________________________
More information about the pypy-issue
mailing list