Skip to content

Commit f667a76

Browse files
markshannondiegorusso
authored andcommitted
pythonGH-117750: When clearing object's dict, clear inline values but leave dict attached (pythonGH-117808)
1 parent c0be455 commit f667a76

File tree

3 files changed

+31
-15
lines changed

3 files changed

+31
-15
lines changed

Lib/test/test_class.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,16 @@ class C: pass
862862
self.assertFalse(has_inline_values(c))
863863
self.check_100(c)
864864

865+
def test_bug_117750(self):
866+
"Aborted on 3.13a6"
867+
class C:
868+
def __init__(self):
869+
self.__dict__.clear()
870+
871+
obj = C()
872+
self.assertEqual(obj.__dict__, {})
873+
obj.foo = None # Aborted here
874+
self.assertEqual(obj.__dict__, {"foo":None})
865875

866876

867877
if __name__ == '__main__':
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix issue where an object's dict would get out of sync with the object's
2+
internal values when being cleared. ``obj.__dict__.clear()`` now clears the
3+
internal values, but leaves the dict attached to the object.

Objects/dictobject.c

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2681,25 +2681,28 @@ clear_lock_held(PyObject *op)
26812681
interp, PyDict_EVENT_CLEARED, mp, NULL, NULL);
26822682
// We don't inc ref empty keys because they're immortal
26832683
ensure_shared_on_resize(mp);
2684-
2685-
set_keys(mp, Py_EMPTY_KEYS);
2686-
set_values(mp, NULL);
2687-
mp->ma_used = 0;
26882684
mp->ma_version_tag = new_version;
2689-
/* ...then clear the keys and values */
2690-
if (oldvalues != NULL) {
2691-
if (!oldvalues->embedded) {
2692-
n = oldkeys->dk_nentries;
2693-
for (i = 0; i < n; i++)
2694-
Py_CLEAR(oldvalues->values[i]);
2695-
free_values(oldvalues, IS_DICT_SHARED(mp));
2696-
}
2697-
dictkeys_decref(interp, oldkeys, false);
2698-
}
2699-
else {
2685+
mp->ma_used = 0;
2686+
if (oldvalues == NULL) {
2687+
set_keys(mp, Py_EMPTY_KEYS);
27002688
assert(oldkeys->dk_refcnt == 1);
27012689
dictkeys_decref(interp, oldkeys, IS_DICT_SHARED(mp));
27022690
}
2691+
else {
2692+
n = oldkeys->dk_nentries;
2693+
for (i = 0; i < n; i++) {
2694+
Py_CLEAR(oldvalues->values[i]);
2695+
}
2696+
if (oldvalues->embedded) {
2697+
oldvalues->size = 0;
2698+
}
2699+
else {
2700+
set_values(mp, NULL);
2701+
set_keys(mp, Py_EMPTY_KEYS);
2702+
free_values(oldvalues, IS_DICT_SHARED(mp));
2703+
dictkeys_decref(interp, oldkeys, false);
2704+
}
2705+
}
27032706
ASSERT_CONSISTENT(mp);
27042707
}
27052708

0 commit comments

Comments
 (0)