Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
121a4d4
Fix memory safety race condition in CPython 3.13 free-threaded mode
rodrigobnogueira Apr 12, 2026
3cdfed9
Add author attribution to changelog entry
rodrigobnogueira Apr 12, 2026
7dd9068
Fix C23 label-at-end-of-compound-statement warnings
rodrigobnogueira Apr 12, 2026
718a106
Simplify free-threading test to avoid debug assertion abort
rodrigobnogueira Apr 12, 2026
a1add47
Add coverage pragmas to test exception handlers
rodrigobnogueira Apr 12, 2026
ab0b478
test: add pragma no cover to RuntimeError handler in free threading t…
rodrigobnogueira Apr 12, 2026
469dda9
Address review feedback: use fixtures, RST roles, and modern type syntax
rodrigobnogueira May 2, 2026
9d4e097
Warn when pure-Python fallback is used on free-threaded CPython
rodrigobnogueira May 4, 2026
e4cab00
Add test for pure-Python free-threaded warning
rodrigobnogueira May 4, 2026
31d372c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 4, 2026
44192cb
Merge branch 'master' into fix-free-threaded-race-condition
rodrigobnogueira Jul 5, 2026
4079a3e
Move the traceback import to the module top
rodrigobnogueira Jul 5, 2026
e7b2b7f
Merge remote-tracking branch 'upstream/master' into fix-free-threaded…
rodrigobnogueira Jul 13, 2026
b3b4434
Use RST roles in the changelog fragment
rodrigobnogueira Jul 13, 2026
7f70468
Merge remote-tracking branch 'upstream/master' into fix-free-threaded…
rodrigobnogueira Aug 9, 2026
3b6e73f
Lock the source multidict when reading its hash table
rodrigobnogueira Aug 9, 2026
75ae501
Resolve the extend source once instead of twice
rodrigobnogueira Aug 9, 2026
d068315
Restore the locking notes and match them to the code
rodrigobnogueira Aug 9, 2026
ad8f6fb
Keep the consistency checks inside the critical section
rodrigobnogueira Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGES/1317.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Fixed a memory-safety race condition resulting in segmentation faults
(use-after-free) when iterating and modifying a :class:`~multidict.MultiDict`
concurrently in CPython free-threaded mode (3.13t+). Read and write accesses
to the internal ``md->keys`` buffer are now wrapped in
:c:macro:`Py_BEGIN_CRITICAL_SECTION`.

Operations that read a second multidict, namely the copy constructors,
:meth:`~multidict.MultiDict.extend`, :meth:`~multidict.MultiDict.update` and
:meth:`~multidict.MultiDict.merge`, now lock both objects with
:c:macro:`Py_BEGIN_CRITICAL_SECTION2`. Previously only the destination was
locked, so a concurrent insertion could resize the source and free the entry
array being walked.

The consistency checks compiled into debug builds no longer run outside the
critical section they belong to. They walk the whole table, so on a debug
free-threaded build one thread could abort on another thread's transient
state, or read an array a third thread had already freed. Most of them
duplicated a check that the ``md_*`` helpers already perform under the lock
and were removed
-- by :user:`rodrigobnogueira`.
20 changes: 20 additions & 0 deletions multidict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@
getversion,
istr,
)

if not TYPE_CHECKING:
import sys
import warnings

# ``sys._is_gil_enabled`` is CPython-private, and this branch is taken
# on alternative implementations too (``_compat`` forces it on PyPy),
# so probe for the attribute rather than inferring it from the version.
# A diagnostic must not be able to break the import it diagnoses.
if not getattr(sys, "_is_gil_enabled", lambda: True)():
warnings.warn(
"The multidict C extension is not in use, either because it "
"is unavailable or because MULTIDICT_NO_EXTENSIONS is set. "
"The pure-Python fallback is not thread-safe under "
"free-threaded CPython (GIL disabled): concurrent mutation "
"can leave a MultiDict internally inconsistent, so confine "
"each instance to one thread.",
RuntimeWarning,
stacklevel=2,
)
else:
from collections.abc import ItemsView, KeysView, ValuesView

Expand Down
Loading
Loading