Title: Free-threaded build: reading a sys._current_frames() frame is a use-after-free · Issue #152355 · python/cpython · GitHub
Open Graph Title: Free-threaded build: reading a sys._current_frames() frame is a use-after-free · Issue #152355 · python/cpython
X Title: Free-threaded build: reading a sys._current_frames() frame is a use-after-free · Issue #152355 · python/cpython
Description: Crash report What happened? frame_read_sync.patch Free-threaded build: reading a sys._current_frames() frame is a use-after-free Affects: free-threaded build only (--disable-gil; python3.13t, PYTHON_GIL=0). The default (GIL) build is saf...
Open Graph Description: Crash report What happened? frame_read_sync.patch Free-threaded build: reading a sys._current_frames() frame is a use-after-free Affects: free-threaded build only (--disable-gil; python3.13t, PYTHO...
X Description: Crash report What happened? frame_read_sync.patch Free-threaded build: reading a sys._current_frames() frame is a use-after-free Affects: free-threaded build only (--disable-gil; python3.13t, PYTHO...
Opengraph URL: https://github.com/python/cpython/issues/152355
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Free-threaded build: reading a sys._current_frames() frame is a use-after-free","articleBody":"# Crash report\n\n### What happened?\n\n[frame_read_sync.patch](https://github.com/user-attachments/files/29399904/frame_read_sync.patch)\n\n# Free-threaded build: reading a `sys._current_frames()` frame is a use-after-free\n\n**Affects:** free-threaded build only (`--disable-gil`; `python3.13t`, `PYTHON_GIL=0`). The default (GIL) build is safe — the GIL serializes it.\n\n`sys._current_frames()` returns `PyFrameObject`s whose `f_frame` points at **another running thread's live `_PyInterpreterFrame`**. Reading any attribute (`f_lineno`, `f_lasti`, `f_globals`, …) dereferences that frame with **no synchronization** while the owning thread concurrently materializes/pops it (`take_ownership`, `Python/frame.c`). So **pure-Python code can segfault the interpreter** (use-after-free).\n\nThis is documented as unsafe in the free-threading HOWTO, but it is a *memory-safety crash reachable from pure Python*. It is the gap left by **gh-117300** (PR #117301, closed): that change stop-the-world's only the *dict snapshot*, not the subsequent frame-attribute reads — which is why the HOWTO's \"may crash\" warning *post-dates* the fix. ThreadSanitizer on a free-threaded build flags the race in `frame_getlineno` ↔ `take_ownership` / `_PyFrame_GetCode`.\n\n## Related\n\n- **gh-117300** / PR #117301 (closed, @colesbury) — the parent: STW'd the snapshot only; this is the remaining read-path race.\n- **DataDog dd-trace-py #13567** — the same UAF in the wild: a production profiler takes a fatal SIGSEGV dereferencing a stale frame from `sys._current_frames()` / `_PyThread_CurrentFrames`.\n- **gh-106883** — a related (different) hazard: deadlock when using `sys._current_frames` under threads.\n\ncc @colesbury (free-threaded frames / gh-117300).\n\n## Repro (segfaults within seconds on a free-threaded build)\n\n```python\nimport sys, threading\n\ndef recurse(n):\n return recurse(n - 1) if n else 0\n\nstop = False\ndef worker():\n while not stop:\n recurse(60) # constantly pushes/pops _PyInterpreterFrames\n\nt = threading.Thread(target=worker); t.start()\ntry:\n while True:\n for fr in sys._current_frames().values():\n fr.f_lineno # reads the worker's LIVE frame -\u003e use-after-free\nfinally:\n stop = True; t.join()\n```\n\n## Proposed minimal fix — `frame_read_sync.patch`\n\nSerialize the frame reader against `take_ownership` with the frame object's own critical section (`Py_BEGIN_CRITICAL_SECTION(f)`). The reader then sees either the pre-materialize live frame or the post-materialize embedded copy — never a torn `f_frame` nor a freed `_PyInterpreterFrame`. The other attribute readers (`frame_getlasti`, `frame_getglobals`, `frame_getbuiltins`, …) need the same wrap; the patch shows the pattern on `f_lineno` (the repro path).\n\n\u003e **Status: proposed.** Generated against CPython 3.13.13; applies cleanly. NOT yet run against the CPython test suite / TSan oracle — treat as a starting point.\n\n### CPython versions tested on:\n\n3.13\n\n### Operating systems tested on:\n\nLinux\n\n### Output from running 'python -VV' on the command line:\n\nCPython 3.13.13","author":{"url":"https://github.com/robertsdotpm","@type":"Person","name":"robertsdotpm"},"datePublished":"2026-06-27T00:33:16.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":2},"url":"https://github.com/152355/cpython/issues/152355"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:0a7cdb28-df8f-1137-3df5-d7502e86d242 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | B4F8:23D81D:663FB8:86670B:6A530244 |
| html-safe-nonce | f6810af43ef4fb95b05c27be947ec7e767c1dcff83f55ef81c6da55ac1e19212 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCNEY4OjIzRDgxRDo2NjNGQjg6ODY2NzBCOjZBNTMwMjQ0IiwidmlzaXRvcl9pZCI6IjcyMDY0MTQzMTUwNzQ4MTQ1MzIiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | d072dbfa03daccbf534916716693b48dd080796c32e5b6aa534a0de3808da582 |
| hovercard-subject-tag | issue:4755942842 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/152355/issue_layout |
| twitter:image | https://opengraph.githubassets.com/05a19bb453171350fb97bdb21752fca59963d930a0861d7372704231b280d5f0/python/cpython/issues/152355 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/05a19bb453171350fb97bdb21752fca59963d930a0861d7372704231b280d5f0/python/cpython/issues/152355 |
| og:image:alt | Crash report What happened? frame_read_sync.patch Free-threaded build: reading a sys._current_frames() frame is a use-after-free Affects: free-threaded build only (--disable-gil; python3.13t, PYTHO... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | robertsdotpm |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 07a982c1d40157c619b364352b704c3ce66bb332 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width