https://github.com/python/cpython/commit/269638bfc615c0e2b695724051dd558ccf474d43
commit: 269638bfc615c0e2b695724051dd558ccf474d43
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-29T17:56:20Z
summary:

[3.15] gh-154709: Fix out-of-bounds access in dict reverse iterator (GH-154721) 
(GH-154888)

(cherry picked from commit 3fd36fadbe8ad31213b90757d196870213bf07ba)

Co-authored-by: Bhuvansh <[email protected]>

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 29b6361eea4feb..afbd9a96c08d81 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -6225,9 +6225,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]

Reply via email to