From c41df03d334f23d248ada9e2f62ce3304424af3e Mon Sep 17 00:00:00 2001 From: Jiucheng Zang Date: Wed, 24 Jun 2026 18:52:10 -0400 Subject: [PATCH 1/3] Address Review Comments --- Lib/test/test_dict.py | 20 +++++++++++++++++++ ...-06-24-14-05-00.gh-issue-152107.K3jX9p.rst | 3 +++ Objects/dictobject.c | 9 +++++---- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index f26586809238f0e..4730897f1963b7c 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -116,6 +116,26 @@ def test_items(self): self.assertRaises(TypeError, d.items, None) self.assertEqual(repr(dict(a=1).items()), "dict_items([('a', 1)])") + @support.cpython_only + def test_item_iterator_oom(self): + import_helper.import_module('_testcapi') + from test.support.script_helper import assert_python_ok + code = """if 1: + import _testcapi + items = {1: 2, 3: 4}.items() + ballast = [(i, i) for i in range(3000)] + held = [] + for start in range(1, 5): + _testcapi.set_nomemory(start) + try: + held.append(iter(items)) + except MemoryError: + pass + finally: + _testcapi.remove_mem_hooks() + """ + assert_python_ok('-c', code) + def test_views_mapping(self): mappingproxy = type(type.__dict__) class Dict(dict): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst new file mode 100644 index 000000000000000..fadc075711e0dca --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst @@ -0,0 +1,3 @@ +Fix a crash when creating a :class:`dict` item iterator (for example +``iter(d.items())`` or ``reversed(d.items())``) under a memory-allocation +failure. Patch by Jiucheng Zang. \ No newline at end of file diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 9210398ee551de1..f06adc3c26e135f 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5507,6 +5507,7 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype) used = GET_USED(dict); di->di_used = used; di->len = used; + di->di_result = NULL; if (itertype == &PyDictRevIterKey_Type || itertype == &PyDictRevIterItem_Type || itertype == &PyDictRevIterValue_Type) { @@ -5520,6 +5521,10 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype) else { di->di_pos = 0; } + /* gh-152107: track before allocating di_result. A dictiter with a NULL + di_result is a valid state for dictiter_traverse()/dictiter_dealloc(), + so a failure of the allocation below can safely DECREF a tracked di. */ + _PyObject_GC_TRACK(di); if (itertype == &PyDictIterItem_Type || itertype == &PyDictRevIterItem_Type) { di->di_result = _PyTuple_FromPairSteal(Py_None, Py_None); @@ -5528,10 +5533,6 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype) return NULL; } } - else { - di->di_result = NULL; - } - _PyObject_GC_TRACK(di); return (PyObject *)di; } From 2886cb8f5e3877153dfdd523007f1fa3a26d5e44 Mon Sep 17 00:00:00 2001 From: Jiucheng Zang Date: Wed, 24 Jun 2026 18:55:09 -0400 Subject: [PATCH 2/3] Fix formatting of comment in dictiter_new function --- Objects/dictobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index f06adc3c26e135f..f6d2a6e43b6186c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5522,8 +5522,8 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype) di->di_pos = 0; } /* gh-152107: track before allocating di_result. A dictiter with a NULL - di_result is a valid state for dictiter_traverse()/dictiter_dealloc(), - so a failure of the allocation below can safely DECREF a tracked di. */ + di_result is a valid state for dictiter_traverse()/dictiter_dealloc(), + so a failure of the allocation below can safely DECREF a tracked di. */ _PyObject_GC_TRACK(di); if (itertype == &PyDictIterItem_Type || itertype == &PyDictRevIterItem_Type) { From 309c9a7353953439778d9bd18f7a11795e173b4d Mon Sep 17 00:00:00 2001 From: Jiucheng Zang Date: Wed, 24 Jun 2026 18:57:22 -0400 Subject: [PATCH 3/3] Fix crash in dict item iterator creation under memory-allocation failure --- .../2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst index fadc075711e0dca..a8f5a99ee065242 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-24-14-05-00.gh-issue-152107.K3jX9p.rst @@ -1,3 +1,3 @@ Fix a crash when creating a :class:`dict` item iterator (for example ``iter(d.items())`` or ``reversed(d.items())``) under a memory-allocation -failure. Patch by Jiucheng Zang. \ No newline at end of file +failure. Patch by Jiucheng Zang.