Skip to content

Commit 57fb030

Browse files
committed
gh-154709: Fix out-of-bounds access in dict reverse iterator
1 parent b618874 commit 57fb030

2 files changed

Lines changed: 25 additions & 0 deletions

File tree

Lib/test/test_dict.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,21 @@ def __init__(self, x, y):
14031403
self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
14041404
self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
14051405

1406+
def test_reversed_dict_after_clear_and_restore(self):
1407+
d = {}
1408+
for i in range(1000):
1409+
d[f"k{i}"] = i
1410+
1411+
for i in range(1, 1000):
1412+
del d[f"k{i}"]
1413+
1414+
it = reversed(d)
1415+
1416+
d.clear()
1417+
d["k0"] = 0
1418+
1419+
self.assertEqual(list(it), [])
1420+
14061421
def test_dict_copy_order(self):
14071422
# bpo-34320
14081423
od = collections.OrderedDict([('a', 1), ('b', 2)])

Objects/dictobject.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6272,13 +6272,23 @@ dictreviter_iter_lock_held(PyDictObject *d, PyObject *self)
62726272
if (i < 0) {
62736273
goto fail;
62746274
}
6275+
62756276
if (_PyDict_HasSplitTable(d)) {
6277+
if (i >= d->ma_used) {
6278+
goto fail;
6279+
}
6280+
62766281
int index = get_index_from_order(d, i);
62776282
key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(k)[index].me_key);
62786283
value = d->ma_values->values[index];
62796284
assert (value != NULL);
62806285
}
62816286
else {
6287+
Py_ssize_t n = k->dk_nentries;
6288+
if (i >= n) {
6289+
goto fail;
6290+
}
6291+
62826292
if (DK_IS_UNICODE(k)) {
62836293
PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
62846294
while (entry_ptr->me_value == NULL) {

0 commit comments

Comments
 (0)