https://github.com/python/cpython/commit/055e6b2891985b9ac88325c2bb544df9e3aa5a0d commit: 055e6b2891985b9ac88325c2bb544df9e3aa5a0d branch: 3.15 author: Miss Islington (bot) <[email protected]> committer: cmaloney <[email protected]> date: 2026-11-08T00:01:24Z summary:
[3.15] gh-148891: prevent crash in HAMT caused by GC during traverse (GH-148928) (#161593) gh-148891: prevent crash in HAMT caused by GC during traverse (GH-148928) `_PyHamt_Assoc` allocates HAMT nodes, which can trigger GC. A weakref callback or finaliser fired during GC could re-enter `contextvar_set`, replacing `ctx->ctx_vars` via `Py_SETREF` and freeing the old HAMT while `_PyHamt_Assoc` was still traversing it, causing a use-after-free. Hold a strong reference to `ctx->ctx_vars` during the `_PyHamt_Assoc` call, so that a re-entrant free cannot affect the HAMT being traversed. (cherry picked from commit 1798d4fb3ca0e1cd8f9e6ab0ac99a0a9fb1f7527) Co-authored-by: Thomas Kowalski <[email protected]> files: A Misc/NEWS.d/next/Core_and_Builtins/2026-04-23-08-36-47.gh-issue-148891.AMMHow.rst M Python/context.c diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-23-08-36-47.gh-issue-148891.AMMHow.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-23-08-36-47.gh-issue-148891.AMMHow.rst new file mode 100644 index 000000000000000..bae5c1366ca6a2c --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-23-08-36-47.gh-issue-148891.AMMHow.rst @@ -0,0 +1 @@ +Fix a crash in :func:`contextvars.Context.run` where a GC invocation could free the current HAMT during traverse. diff --git a/Python/context.c b/Python/context.c index 29c483d2dc90d68..e4e58df0f96c98f 100644 --- a/Python/context.c +++ b/Python/context.c @@ -866,8 +866,13 @@ contextvar_set(PyContextVar *var, PyObject *val) return -1; } + // gh-148891: Make a strong reference so a GC during _PyHamt_Assoc will + // not free the HAMT during traversal. + PyHamtObject *old_vars = context_get_current_vars(ctx); + Py_INCREF(old_vars); PyHamtObject *new_vars = _PyHamt_Assoc( - context_get_current_vars(ctx), (PyObject *)var, val); + old_vars, (PyObject *)var, val); + Py_DECREF(old_vars); if (new_vars == NULL) { return -1; } @@ -894,8 +899,12 @@ contextvar_del(PyContextVar *var) return -1; } + // gh-148891: Make a strong reference so a GC during _PyHamt_Without will + // not free the HAMT during traversal. PyHamtObject *vars = context_get_current_vars(ctx); + Py_INCREF(vars); PyHamtObject *new_vars = _PyHamt_Without(vars, (PyObject *)var); + Py_DECREF(vars); if (new_vars == NULL) { return -1; } _______________________________________________ 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]
