https://github.com/python/cpython/commit/784e076a10e828f383282df8a4b993a1b821f547
commit: 784e076a10e828f383282df8a4b993a1b821f547
branch: main
author: Mark Shannon <[email protected]>
committer: markshannon <[email protected]>
date: 2024-04-15T14:45:05+01:00
summary:
GH-117750: When clearing object's dict, clear inline values but leave dict
attached (GH-117808)
files:
A Misc/NEWS.d/next/Core and
Builtins/2024-04-12-11-19-18.gh-issue-117750.YttK6h.rst
M Lib/test/test_class.py
M Objects/dictobject.c
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py
index 4c1814142736e3..a9cfd8df691845 100644
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -862,6 +862,16 @@ class C: pass
self.assertFalse(has_inline_values(c))
self.check_100(c)
+ def test_bug_117750(self):
+ "Aborted on 3.13a6"
+ class C:
+ def __init__(self):
+ self.__dict__.clear()
+
+ obj = C()
+ self.assertEqual(obj.__dict__, {})
+ obj.foo = None # Aborted here
+ self.assertEqual(obj.__dict__, {"foo":None})
if __name__ == '__main__':
diff --git a/Misc/NEWS.d/next/Core and
Builtins/2024-04-12-11-19-18.gh-issue-117750.YttK6h.rst b/Misc/NEWS.d/next/Core
and Builtins/2024-04-12-11-19-18.gh-issue-117750.YttK6h.rst
new file mode 100644
index 00000000000000..d7cf5d6e57d0cb
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and
Builtins/2024-04-12-11-19-18.gh-issue-117750.YttK6h.rst
@@ -0,0 +1,3 @@
+Fix issue where an object's dict would get out of sync with the object's
+internal values when being cleared. ``obj.__dict__.clear()`` now clears the
+internal values, but leaves the dict attached to the object.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 9c38ef2314684f..003a03fd741702 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -2681,25 +2681,28 @@ clear_lock_held(PyObject *op)
interp, PyDict_EVENT_CLEARED, mp, NULL, NULL);
// We don't inc ref empty keys because they're immortal
ensure_shared_on_resize(mp);
-
- set_keys(mp, Py_EMPTY_KEYS);
- set_values(mp, NULL);
- mp->ma_used = 0;
mp->ma_version_tag = new_version;
- /* ...then clear the keys and values */
- if (oldvalues != NULL) {
- if (!oldvalues->embedded) {
- n = oldkeys->dk_nentries;
- for (i = 0; i < n; i++)
- Py_CLEAR(oldvalues->values[i]);
- free_values(oldvalues, IS_DICT_SHARED(mp));
- }
- dictkeys_decref(interp, oldkeys, false);
- }
- else {
+ mp->ma_used = 0;
+ if (oldvalues == NULL) {
+ set_keys(mp, Py_EMPTY_KEYS);
assert(oldkeys->dk_refcnt == 1);
dictkeys_decref(interp, oldkeys, IS_DICT_SHARED(mp));
}
+ else {
+ n = oldkeys->dk_nentries;
+ for (i = 0; i < n; i++) {
+ Py_CLEAR(oldvalues->values[i]);
+ }
+ if (oldvalues->embedded) {
+ oldvalues->size = 0;
+ }
+ else {
+ set_values(mp, NULL);
+ set_keys(mp, Py_EMPTY_KEYS);
+ free_values(oldvalues, IS_DICT_SHARED(mp));
+ dictkeys_decref(interp, oldkeys, false);
+ }
+ }
ASSERT_CONSISTENT(mp);
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]