[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