aboutsummaryrefslogtreecommitdiff
path: root/pypy
diff options
context:
space:
mode:
authorCarl Friedrich Bolz-Tereick <cfbolz@gmx.de>2021-01-30 16:05:53 +0100
committerCarl Friedrich Bolz-Tereick <cfbolz@gmx.de>2021-01-30 16:05:53 +0100
commitc434800b6f07f582ae460405251512b4433bf4a6 (patch)
tree1249438f70c5e2081858b012ad07ebf445983f1a /pypy
parentalways go through _set_mapdict_map (diff)
downloadpypy-c434800b6f07f582ae460405251512b4433bf4a6.tar.gz
pypy-c434800b6f07f582ae460405251512b4433bf4a6.tar.bz2
pypy-c434800b6f07f582ae460405251512b4433bf4a6.zip
pretty subtle bug: when iterating over a map dict, some items would go missing!
Diffstat (limited to 'pypy')
-rw-r--r--pypy/objspace/std/mapdict.py8
-rw-r--r--pypy/objspace/std/test/test_mapdict.py23
2 files changed, 24 insertions, 7 deletions
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
index 6eb944753b..e04266cc98 100644
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -1095,7 +1095,7 @@ class IteratorMixin(object):
def _init(self, strategy, w_dict):
w_obj = strategy.unerase(w_dict.dstorage)
self.w_obj = w_obj
- self.orig_map = curr_map = w_obj._get_mapdict_map()
+ curr_map = w_obj._get_mapdict_map()
# We enumerate non-lazily the attributes, and store them in the
# 'attrs' list. We then walk that list in opposite order. This
# gives an ordering that is more natural (roughly corresponding
@@ -1122,8 +1122,6 @@ class MapDictIteratorKeys(BaseKeyIterator):
def next_key_entry(self):
assert isinstance(self.w_dict.get_strategy(), MapDictStrategy)
- if self.orig_map is not self.w_obj._get_mapdict_map():
- return None
attrs = self.attrs
if len(attrs) > 0:
attr = attrs.pop()
@@ -1141,8 +1139,6 @@ class MapDictIteratorValues(BaseValueIterator):
def next_value_entry(self):
assert isinstance(self.w_dict.get_strategy(), MapDictStrategy)
- if self.orig_map is not self.w_obj._get_mapdict_map():
- return None
attrs = self.attrs
if len(attrs) > 0:
attr = attrs.pop()
@@ -1159,8 +1155,6 @@ class MapDictIteratorItems(BaseItemIterator):
def next_item_entry(self):
assert isinstance(self.w_dict.get_strategy(), MapDictStrategy)
- if self.orig_map is not self.w_obj._get_mapdict_map():
- return None, None
attrs = self.attrs
if len(attrs) > 0:
attr = attrs.pop()
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
index 6cf363fcdb..ebc92bc1df 100644
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -1197,6 +1197,29 @@ class AppTestWithMapDict(object):
for key in d:
assert d[key] == int(key)
+ def test_bug_iter_checks_map_is_wrong(self):
+ # obvious in hindsight, but this test shows that checking that the map
+ # stays the same during a.__dict__ iterations is too strict now
+ class A(object):
+ pass
+
+ # an instance with unboxed storage
+ a = A()
+ a.x = "a"
+ a.y = 1
+ a.z = "b"
+
+ a1 = A()
+ a1.x = "a"
+ a1.y = 1
+ a1.z = "b"
+ a1.y = None # mark the terminator as allow_unboxing = False
+
+ d = a.__dict__
+ # reading a.y during iteration changes the map! now that the iterators
+ # store all the attrs anyway, just remove the check
+ res = list(d.iteritems())
+ assert res == [('x', 'a'), ('y', 1), ('z', 'b')]
class AppTestWithMapDictAndCounters(object):