Skip to content

Commit 0bcdd79

Browse files
BHUVANSH855miss-islington
authored andcommitted
gh-154709: Fix out-of-bounds access in dict reverse iterator (GH-154721)
(cherry picked from commit 3fd36fa) Co-authored-by: Bhuvansh <bhuvanshkataria@gmail.com>
1 parent 6e194b6 commit 0bcdd79

3 files changed

Lines changed: 27 additions & 1 deletion

File tree

Lib/test/test_dict.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,27 @@ def __init__(self, x, y):
14961496
self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
14971497
self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
14981498

1499+
def test_reversed_dict_after_clear_and_restore(self):
1500+
d = {}
1501+
for i in range(1000):
1502+
d[f"k{i}"] = i
1503+
1504+
for i in range(1, 1000):
1505+
del d[f"k{i}"]
1506+
1507+
iterators = (
1508+
reversed(d),
1509+
reversed(d.keys()),
1510+
reversed(d.values()),
1511+
reversed(d.items()),
1512+
)
1513+
1514+
d.clear()
1515+
d["k0"] = 0
1516+
1517+
for it in iterators:
1518+
self.assertEqual(list(it), [])
1519+
14991520
def test_dict_copy_order(self):
15001521
# bpo-34320
15011522
od = collections.OrderedDict([('a', 1), ('b', 2)])
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an out-of-bounds access in reverse dictionary iterators when the
2+
underlying dictionary is cleared and modified after the iterator is created.

Objects/dictobject.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5688,9 +5688,12 @@ dictreviter_iter_lock_held(PyDictObject *d, PyObject *self)
56885688
int index = get_index_from_order(d, i);
56895689
key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(k)[index].me_key);
56905690
value = d->ma_values->values[index];
5691-
assert (value != NULL);
5691+
assert(value != NULL);
56925692
}
56935693
else {
5694+
if (i >= k->dk_nentries) {
5695+
goto fail;
5696+
}
56945697
if (DK_IS_UNICODE(k)) {
56955698
PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
56965699
while (entry_ptr->me_value == NULL) {

0 commit comments

Comments
 (0)