summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDino Viehland <dinoviehland@meta.com>2024-07-30 16:13:31 (GMT)
committerGitHub <noreply@github.com>2024-07-30 16:13:31 (GMT)
commit11292ab93561e1759c9a992949e3ceae5447411c (patch)
tree795e8fa31aa6accbd27cca9086880c01d737f420
parent0d6324c6b3a9f6aa25ec9228d24d9e23294afcc9 (diff)
downloadcpython-11292ab93561e1759c9a992949e3ceae5447411c.zip
cpython-11292ab93561e1759c9a992949e3ceae5447411c.tar.gz
cpython-11292ab93561e1759c9a992949e3ceae5447411c.tar.bz2
[3.13] gh-122208: Don't delivery PyDict_EVENT_ADDED until it can't fail (#122326)
Don't delivery PyDict_EVENT_ADDED until it can't fail
-rw-r--r--Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-21-26-33.gh-issue-122208.z8KHsY.rst1
-rw-r--r--Objects/dictobject.c19
2 files changed, 9 insertions, 11 deletions
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-21-26-33.gh-issue-122208.z8KHsY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-21-26-33.gh-issue-122208.z8KHsY.rst
new file mode 100644
index 0000000..e4a89d1
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-07-26-21-26-33.gh-issue-122208.z8KHsY.rst
@@ -0,0 +1 @@
+Dictionary watchers now only deliver the PyDict_EVENT_ADDED event when the insertion is in a known good state to succeed.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index e9861d4..dedcd23 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1686,6 +1686,10 @@ insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
}
}
+ uint64_t new_version = _PyDict_NotifyEvent(
+ interp, PyDict_EVENT_ADDED, mp, key, value);
+ 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);
@@ -1702,6 +1706,7 @@ insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
STORE_VALUE(ep, value);
STORE_HASH(ep, hash);
}
+ mp->ma_version_tag = new_version;
STORE_KEYS_USABLE(mp->ma_keys, mp->ma_keys->dk_usable - 1);
STORE_KEYS_NENTRIES(mp->ma_keys, mp->ma_keys->dk_nentries + 1);
assert(mp->ma_keys->dk_usable >= 0);
@@ -1805,15 +1810,11 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
if (ix == DKIX_EMPTY) {
assert(!_PyDict_HasSplitTable(mp));
- 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 (insert_combined_dict(interp, mp, hash, key, value) < 0) {
goto Fail;
}
- mp->ma_version_tag = new_version;
STORE_USED(mp, mp->ma_used + 1);
ASSERT_CONSISTENT(mp);
return 0;
@@ -1854,9 +1855,6 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
assert(mp->ma_keys == Py_EMPTY_KEYS);
ASSERT_DICT_LOCKED(mp);
- 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);
@@ -1865,6 +1863,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. */
assert(mp->ma_values == NULL);
@@ -4264,9 +4265,6 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
if (ix == DKIX_EMPTY) {
assert(!_PyDict_HasSplitTable(mp));
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_ADDED, mp, key, default_value);
- mp->ma_keys->dk_version = 0;
value = default_value;
if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
@@ -4279,7 +4277,6 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
MAINTAIN_TRACKING(mp, key, value);
STORE_USED(mp, mp->ma_used + 1);
- mp->ma_version_tag = new_version;
assert(mp->ma_keys->dk_usable >= 0);
ASSERT_CONSISTENT(mp);
if (result) {