https://github.com/python/cpython/commit/3fd36fadbe8ad31213b90757d196870213bf07ba
commit: 3fd36fadbe8ad31213b90757d196870213bf07ba
branch: main
author: Bhuvansh <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-29T20:26:45+03:00
summary:
gh-154709: Fix out-of-bounds access in dict reverse iterator (GH-154721)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-09-07-41.gh-issue-154709.M2uZ76.rst
M Lib/test/test_dict.py
M Objects/dictobject.c
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index dc31d403b837ad..1e665c86303078 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -1403,6 +1403,27 @@ def __init__(self, x, y):
self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
+ def test_reversed_dict_after_clear_and_restore(self):
+ d = {}
+ for i in range(1000):
+ d[f"k{i}"] = i
+
+ for i in range(1, 1000):
+ del d[f"k{i}"]
+
+ iterators = (
+ reversed(d),
+ reversed(d.keys()),
+ reversed(d.values()),
+ reversed(d.items()),
+ )
+
+ d.clear()
+ d["k0"] = 0
+
+ for it in iterators:
+ self.assertEqual(list(it), [])
+
def test_dict_copy_order(self):
# bpo-34320
od = collections.OrderedDict([('a', 1), ('b', 2)])
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-09-07-41.gh-issue-154709.M2uZ76.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-09-07-41.gh-issue-154709.M2uZ76.rst
new file mode 100644
index 00000000000000..6eb1ce6a8b6970
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-26-09-07-41.gh-issue-154709.M2uZ76.rst
@@ -0,0 +1,2 @@
+Fix an out-of-bounds access in reverse dictionary iterators when the
+underlying dictionary is cleared and modified after the iterator is created.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index c650aa456d2cc9..74b6d5d779a064 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -6276,9 +6276,12 @@ dictreviter_iter_lock_held(PyDictObject *d, PyObject
*self)
int index = get_index_from_order(d, i);
key = LOAD_SHARED_KEY(DK_UNICODE_ENTRIES(k)[index].me_key);
value = d->ma_values->values[index];
- assert (value != NULL);
+ assert(value != NULL);
}
else {
+ if (i >= k->dk_nentries) {
+ goto fail;
+ }
if (DK_IS_UNICODE(k)) {
PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
while (entry_ptr->me_value == NULL) {
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]