Skip to content

Commit 07c4935

Browse files
committed
Treat the dictionary as owning values, not the object.
1 parent 2fa09a9 commit 07c4935

2 files changed

Lines changed: 12 additions & 8 deletions

File tree

Lib/test/test_dict.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,9 +1487,9 @@ def make_pairs():
14871487
self.assertGreaterEqual(eq_count, 1)
14881488

14891489
def test_overwrite_managed_dict(self):
1490-
# GH-130327: Overwriting an object's managed dict incorrectly stored
1491-
# the new dictionary in the managed dict pointer for objects supporting
1492-
# inline values, leading to early clearing of the dictionary
1490+
# GH-130327: Overwriting an object's managed dictionary with another object's
1491+
# skipped traversal in favor of inline values, causing the GC to believe that
1492+
# the __dict__ wasn't reachable.
14931493
import gc
14941494

14951495
class Shenanigans:

Objects/dictobject.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4577,10 +4577,8 @@ dict_traverse(PyObject *op, visitproc visit, void *arg)
45774577

45784578
if (DK_IS_UNICODE(keys)) {
45794579
if (_PyDict_HasSplitTable(mp)) {
4580-
if (!mp->ma_values->embedded) {
4581-
for (i = 0; i < n; i++) {
4582-
Py_VISIT(mp->ma_values->values[i]);
4583-
}
4580+
for (i = 0; i < n; i++) {
4581+
Py_VISIT(mp->ma_values->values[i]);
45844582
}
45854583
}
45864584
else {
@@ -7150,6 +7148,13 @@ PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
71507148
if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
71517149
return 0;
71527150
}
7151+
PyDictObject *dict = _PyObject_ManagedDictPointer(obj)->dict;
7152+
if (dict != NULL) {
7153+
// GH-130327: If there's a managed dictionary available, we should
7154+
// *always* traverse it, including when inline values are available.
7155+
Py_VISIT(dict);
7156+
return 0;
7157+
}
71537158
if (tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
71547159
PyDictValues *values = _PyObject_InlineValues(obj);
71557160
if (values->valid) {
@@ -7159,7 +7164,6 @@ PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
71597164
return 0;
71607165
}
71617166
}
7162-
Py_VISIT(_PyObject_ManagedDictPointer(obj)->dict);
71637167
return 0;
71647168
}
71657169

0 commit comments

Comments
 (0)