https://github.com/python/cpython/commit/f9132f1c555f0e47d7e38251f96adaf0355f9c08
commit: f9132f1c555f0e47d7e38251f96adaf0355f9c08
branch: main
author: Christian Aurich Zanettini Martins <[email protected]>
committer: methane <[email protected]>
date: 2026-10-13T03:07:34Z
summary:

gh-159285: Fix crash when copying an empty dict fails with MemoryError (#159286)

copy_lock_held_untracked() asserted that the new empty dict was not
tracked by the GC without checking whether its allocation had failed,
so a debug build dereferenced NULL instead of raising MemoryError. This
affected dict.copy(), PyDict_Copy() and _PyDict_CopyAsDict(), which
type() uses for the class namespace.

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-10-12-23-32-50.gh-issue-159285.nlLuwQ.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 26bdaa9d6a35b7..9d013e3d2caa1c 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -479,6 +479,13 @@ def test_copy_noncompact(self):
         d2 = d.copy()
         self.assertEqual(d2, d)
 
+    @support.nomemtest
+    def test_copy_empty_no_memory(self):
+        import _testcapi
+        d = {}
+        with self.assertRaises(MemoryError):
+            _testcapi.call_with_nomemory(0, 0, d.copy)
+
     def test_get(self):
         d = {}
         self.assertIs(d.get('c'), None)
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-12-23-32-50.gh-issue-159285.nlLuwQ.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-12-23-32-50.gh-issue-159285.nlLuwQ.rst
new file mode 100644
index 00000000000000..0cb795f8309f73
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-12-23-32-50.gh-issue-159285.nlLuwQ.rst
@@ -0,0 +1,2 @@
+Fix a crash in a debug build when copying an empty :class:`dict` fails with
+:exc:`MemoryError`. Patch by Christian Aurich Zanettini Martins.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index eed9bd92c55bf2..13c9e2e4b395ab 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -4497,7 +4497,7 @@ copy_lock_held_untracked(PyObject *o, int as_frozendict)
         else {
             d = dict_new_untracked(&PyDict_Type);
         }
-        assert(!_PyObject_GC_IS_TRACKED(d));
+        assert(d == NULL || !_PyObject_GC_IS_TRACKED(d));
         return d;
     }
 

_______________________________________________
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