• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aio-libs / multidict / 36531123640
87%

Build:
DEFAULT BRANCH: master
Ran 29 Sep 2026 06:28AM UTC
Jobs 1
Files 46
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

29 Sep 2026 06:01AM UTC coverage: 87.125%. Remained the same
36531123640

push

github

web-flow
Refuse a mutation from a collection run inside to_dict() (#1630)

<!-- Thank you for your contribution! -->

## What do these changes do?

On Python 3.10 and 3.11, allocating a GC-tracked object can run a
garbage collection on the spot, and its finalizers can mutate the
multidict. `to_dict()` allocates each key's value list with
`PyList_New()` and then read the matched entry, possibly from a table
the finalizer had freed. It now checks the version right after the
allocation and raises `RuntimeError`, as it already does when a key's
`__hash__()` mutates the multidict. 3.12 and later run collections from
the eval loop, never inside the call, so they are unaffected.

The pure-Python implementation already refuses the mutation through its
version check.

## Are there changes in behavior for the user?

Yes, on 3.10 and 3.11: `RuntimeError` instead of a use-after-free.

## Is it a substantial burden for the maintainers to support this?

No, one version check.

## Related issue number

Found by the finalizer audit in #1631.

## Checklist

- [x] I think the code is well written
- [x] Unit tests for the changes exist
- [x] Documentation reflects the changes
- [ ] If you provide code modification, please add yourself to
`CONTRIBUTORS.txt` (N/A)
- [x] Add a new news fragment into the `CHANGES/` folder
- [x] `make doc-spelling` passes and any new technical words are added
to `docs/spelling_wordlist.txt`

<details>
<summary>Agent run details (optional, for reviewers)</summary>

New `test_to_dict_refuses_mutation_from_a_collection` (3.10 and 3.11
only; later versions never collect mid-call) arms a collection at each
of 12 allocation offsets, records whether the finalizer ran inside
`to_dict()`, and requires at least one round to land inside and every
such round to be refused. With the guard removed it segfaults on 3.10.17
and 3.11.13, release and debug builds alike; with it, it passes on both
backends.

Tests, one venv and tree copy per leg, full suite: GIL 3.14.7 ... (continued)

789 of 1578 branches covered (50.0%)

Branch coverage included in aggregate %.

48 of 48 new or added lines in 1 file covered. (100.0%)

8881 of 9521 relevant lines covered (93.28%)

1.87 hits per line

Jobs
ID Job ID Ran Files Coverage
1 MyPy - 36531123640.1 29 Sep 2026 06:28AM UTC 92
87.12
GitHub Action Run
Source Files on build 36531123640
  • Tree
  • List 46
  • Changed 2
  • Source Changed 0
  • Coverage Changed 2
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #36531123640
  • 74b96d79 on github
  • Prev Build on master (#36529007782)
  • Next Build on master (#36536336556)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc