Skip to content

Commit 5d26a04

Browse files
authored
[3.14] gh-143189: fix insertdict() for non-Unicode key (GH-143285) (#143771)
1 parent af89f7c commit 5d26a04

File tree

3 files changed

+27
-2
lines changed

3 files changed

+27
-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+
self.assertIsInstance(list(d)[0], MyStr)
1650+
16321651

16331652
class CAPITest(unittest.TestCase):
16341653

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix crash when inserting a non-:class:`str` key into a split table
2+
dictionary when the key matches an existing key in the split table
3+
but has no corresponding value in the dict.

Objects/dictobject.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,7 +1826,7 @@ static int
18261826
insertdict(PyInterpreterState *interp, PyDictObject *mp,
18271827
PyObject *key, Py_hash_t hash, PyObject *value)
18281828
{
1829-
PyObject *old_value;
1829+
PyObject *old_value = NULL;
18301830
Py_ssize_t ix;
18311831

18321832
ASSERT_DICT_LOCKED(mp);
@@ -1847,11 +1847,14 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
18471847
goto Fail;
18481848
}
18491849

1850-
if (ix == DKIX_EMPTY) {
1850+
if (old_value == NULL) {
18511851
// insert_combined_dict() will convert from non DICT_KEYS_GENERAL table
18521852
// into DICT_KEYS_GENERAL table if key is not Unicode.
18531853
// We don't convert it before _Py_dict_lookup because non-Unicode key
18541854
// may change generic table into Unicode table.
1855+
//
1856+
// NOTE: ix may not be DKIX_EMPTY because split table may have key
1857+
// without value.
18551858
if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
18561859
goto Fail;
18571860
}

0 commit comments

Comments
 (0)