]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-143189: fix insertdict() for non-Unicode key (GH-143285) (#143772)
authorInada Naoki <songofacandy@gmail.com>
Tue, 13 Jan 2026 10:12:38 +0000 (19:12 +0900)
committerGitHub <noreply@github.com>
Tue, 13 Jan 2026 10:12:38 +0000 (10:12 +0000)
Lib/test/test_dict.py
Misc/NEWS.d/next/Core and Builtins/2025-12-30-06-48-48.gh-issue-143189.in_sv2.rst [new file with mode: 0644]
Objects/dictobject.c

index c7b6f64b53b42f19305e5e1efc1c7510c126af4a..52ef0c14ea3a6406b5bdb1f71989cd9205bf19cb 100644 (file)
@@ -1655,6 +1655,7 @@ class DictTest(unittest.TestCase):
                 self.assertGreaterEqual(eq_count, 1)
 
     def test_clear_at_lookup(self):
+        # gh-140551 dict crash if clear is called at lookup stage
         class X:
             def __hash__(self):
                 return 1
@@ -1675,6 +1676,8 @@ class DictTest(unittest.TestCase):
         self.assertEqual(len(d), 1)
 
     def test_split_table_update_with_str_subclass(self):
+        # gh-142218: inserting into a split table dictionary with a non str
+        # key that matches an existing key.
         class MyStr(str): pass
         class MyClass: pass
         obj = MyClass()
@@ -1682,6 +1685,22 @@ class DictTest(unittest.TestCase):
         obj.__dict__[MyStr('attr')] = 2
         self.assertEqual(obj.attr, 2)
 
+    def test_split_table_insert_with_str_subclass(self):
+        # gh-143189: inserting into split table dictionary with a non str
+        # key that matches an existing key in the shared table but not in
+        # the dict yet.
+
+        class MyStr(str): pass
+        class MyClass: pass
+
+        obj = MyClass()
+        obj.attr1 = 1
+
+        obj2 = MyClass()
+        d = obj2.__dict__
+        d[MyStr("attr1")] = 2
+        self.assertIsInstance(list(d)[0], MyStr)
+
 
 class CAPITest(unittest.TestCase):
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2025-12-30-06-48-48.gh-issue-143189.in_sv2.rst b/Misc/NEWS.d/next/Core and Builtins/2025-12-30-06-48-48.gh-issue-143189.in_sv2.rst
new file mode 100644 (file)
index 0000000..706b9de
--- /dev/null
@@ -0,0 +1,3 @@
+Fix crash when inserting a non-:class:`str` key into a split table
+dictionary when the key matches an existing key in the split table
+but has no corresponding value in the dict.
index c987af31c45dd1c10d8e7f5bb5b4bf6be04b8568..3e0537c18177a74929296b9c95b16a5b5bf52f2c 100644 (file)
@@ -1832,7 +1832,7 @@ static int
 insertdict(PyInterpreterState *interp, PyDictObject *mp,
            PyObject *key, Py_hash_t hash, PyObject *value)
 {
-    PyObject *old_value;
+    PyObject *old_value = NULL;
     Py_ssize_t ix;
 
     ASSERT_DICT_LOCKED(mp);
@@ -1856,11 +1856,14 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
 
     }
 
-    if (ix == DKIX_EMPTY) {
+    if (old_value == NULL) {
         // insert_combined_dict() will convert from non DICT_KEYS_GENERAL table
         // into DICT_KEYS_GENERAL table if key is not Unicode.
         // We don't convert it before _Py_dict_lookup because non-Unicode key
         // may change generic table into Unicode table.
+        //
+        // NOTE: ix may not be DKIX_EMPTY because split table may have key
+        // without value.
         if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
             goto Fail;
         }