Skip to content

Commit f1e7bcc

Browse files
committed
gh-143189: fix insertdict() for non-Unicode key
When iserting non unicode key into split table, matching Unicode key may be in the shared split table without its value.
1 parent ef834de commit f1e7bcc

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

Lib/test/test_dict.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,7 @@ def __hash__(self):
16021602
d.get(key2)
16031603

16041604
def test_clear_at_lookup(self):
1605+
# gh-140551 dict crash if clear is called at lookup stage
16051606
class X:
16061607
def __hash__(self):
16071608
return 1
@@ -1622,13 +1623,31 @@ def __eq__(self, other):
16221623
self.assertEqual(len(d), 1)
16231624

16241625
def test_split_table_update_with_str_subclass(self):
1626+
# gh-142218: inserting into a split table dictionary with a non str
1627+
# key that matches an existing key.
16251628
class MyStr(str): pass
16261629
class MyClass: pass
16271630
obj = MyClass()
16281631
obj.attr = 1
16291632
obj.__dict__[MyStr('attr')] = 2
16301633
self.assertEqual(obj.attr, 2)
16311634

1635+
def test_split_table_insert_with_str_subclass(self):
1636+
# gh-143189: inserting into split table dictionary with a non str
1637+
# key that matches an existing key in the shared table but not in
1638+
# the dict yet.
1639+
1640+
class MyStr(str): pass
1641+
class MyClass: pass
1642+
1643+
obj = MyClass()
1644+
obj.attr1 = 1
1645+
1646+
obj2 = MyClass()
1647+
d = obj2.__dict__
1648+
d[MyStr("attr1")] = 2
1649+
assert isinstance(list(d)[0], MyStr)
1650+
16321651

16331652
class CAPITest(unittest.TestCase):
16341653

Objects/dictobject.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,7 @@ static int
18771877
insertdict(PyDictObject *mp,
18781878
PyObject *key, Py_hash_t hash, PyObject *value)
18791879
{
1880-
PyObject *old_value;
1880+
PyObject *old_value = NULL;
18811881
Py_ssize_t ix;
18821882

18831883
ASSERT_DICT_LOCKED(mp);
@@ -1898,11 +1898,14 @@ insertdict(PyDictObject *mp,
18981898
goto Fail;
18991899
}
19001900

1901-
if (ix == DKIX_EMPTY) {
1901+
if (old_value == NULL) {
19021902
// insert_combined_dict() will convert from non DICT_KEYS_GENERAL table
19031903
// into DICT_KEYS_GENERAL table if key is not Unicode.
19041904
// We don't convert it before _Py_dict_lookup because non-Unicode key
19051905
// may change generic table into Unicode table.
1906+
//
1907+
// NOTE: ix may not be DKIX_EMPTY because split table may have key
1908+
// without value.
19061909
if (insert_combined_dict(mp, hash, key, value) < 0) {
19071910
goto Fail;
19081911
}

0 commit comments

Comments
 (0)