]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-122208: Don't delivery PyDict_EVENT_ADDED until it can't fail (#122327)
authorDino Viehland <dinoviehland@meta.com>
Tue, 30 Jul 2024 16:13:40 +0000 (09:13 -0700)
committerGitHub <noreply@github.com>
Tue, 30 Jul 2024 16:13:40 +0000 (09:13 -0700)
Don't delivery PyDict_EVENT_ADDED until it can't fail

Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-21-38-47.gh-issue-122208.z8KHsY.rst [new file with mode: 0644]
Objects/dictobject.c

diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-21-38-47.gh-issue-122208.z8KHsY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-21-38-47.gh-issue-122208.z8KHsY.rst
new file mode 100644 (file)
index 0000000..e4a89d1
--- /dev/null
@@ -0,0 +1 @@
+Dictionary watchers now only deliver the PyDict_EVENT_ADDED event when the insertion is in a known good state to succeed.
index 254cd9ad2f9bdad9724da17766ab42ba20e1f8e0..a99f32a9c84c9522473c528fdb0e57b901f96cd3 100644 (file)
@@ -1251,10 +1251,6 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
     MAINTAIN_TRACKING(mp, key, value);
 
     if (ix == DKIX_EMPTY) {
-        uint64_t new_version = _PyDict_NotifyEvent(
-                interp, PyDict_EVENT_ADDED, mp, key, value);
-        /* Insert into new slot. */
-        mp->ma_keys->dk_version = 0;
         assert(old_value == NULL);
         if (mp->ma_keys->dk_usable <= 0) {
             /* Need to resize. */
@@ -1262,6 +1258,11 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
                 goto Fail;
         }
 
+        uint64_t new_version = _PyDict_NotifyEvent(
+                interp, PyDict_EVENT_ADDED, mp, key, value);
+        /* Insert into new slot. */
+        mp->ma_keys->dk_version = 0;
+
         Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
         dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
 
@@ -1335,9 +1336,6 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
 {
     assert(mp->ma_keys == Py_EMPTY_KEYS);
 
-    uint64_t new_version = _PyDict_NotifyEvent(
-            interp, PyDict_EVENT_ADDED, mp, key, value);
-
     int unicode = PyUnicode_CheckExact(key);
     PyDictKeysObject *newkeys = new_keys_object(
             interp, PyDict_LOG_MINSIZE, unicode);
@@ -1346,6 +1344,9 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
         Py_DECREF(value);
         return -1;
     }
+    uint64_t new_version = _PyDict_NotifyEvent(
+            interp, PyDict_EVENT_ADDED, mp, key, value);
+
     /* We don't decref Py_EMPTY_KEYS here because it is immortal. */
     mp->ma_keys = newkeys;
     mp->ma_values = NULL;
@@ -3324,15 +3325,15 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
         return NULL;
 
     if (ix == DKIX_EMPTY) {
-        uint64_t new_version = _PyDict_NotifyEvent(
-                interp, PyDict_EVENT_ADDED, mp, key, defaultobj);
-        mp->ma_keys->dk_version = 0;
         value = defaultobj;
         if (mp->ma_keys->dk_usable <= 0) {
             if (insertion_resize(interp, mp, 1) < 0) {
                 return NULL;
             }
         }
+        uint64_t new_version = _PyDict_NotifyEvent(
+                interp, PyDict_EVENT_ADDED, mp, key, defaultobj);
+        mp->ma_keys->dk_version = 0;
         Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
         dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
         if (DK_IS_UNICODE(mp->ma_keys)) {