Skip to content

gh-132617: Fix dict.update() mutation check #134815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

colesbury
Copy link
Contributor

@colesbury colesbury commented May 27, 2025

Use ma_used instead of ma_keys->dk_nentries for modification check so that we only check if the dictionary is modified, not if new keys are added to a different dictionary that shared the same keys object.

Use `ma_used` instead of `ma_keys->dk_nentries` for modification check
so that we only check if the dictionary is modified, not if new keys are
added to a different dictionary that shared the same keys object.
@colesbury colesbury added needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes labels May 27, 2025
@colesbury colesbury requested a review from mpage May 27, 2025 20:45
@colesbury colesbury changed the title gh-132617: Fix dict.update() mutation check gh-132617: Fix dict.update() mutation check May 27, 2025
@@ -3858,7 +3858,7 @@ dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *othe
}
}

Py_ssize_t orig_size = other->ma_keys->dk_nentries;
Py_ssize_t orig_size = other->ma_used;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ma_used is too weak. It cannot detect del d["a"]; d["b"] = None.

For better check:

  • For all table, check other->ma_keys is not changed.
  • For combined table, check other->ma_keys->dk_nentries is not changed.
  • For split table, check other->ma_values->size is not changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the same condition we use in iterators and elsewhere. I don't think we should strengthen any of the checks. These are heuristic checks, they're not going to be perfect, but if we decide to do so, I think we should do that in a subsequent PR and not backport that change.

cpython/Objects/dictobject.c

Lines 5169 to 5174 in 469a564

if (di->di_used != d->ma_used) {
PyErr_SetString(PyExc_RuntimeError,
"dictionary changed size during iteration");
di->di_used = -1; /* Make this state sticky */
return NULL;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting merge needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants