René's URL Explorer Experiment


Title: Use-after-free under MemoryError: opcode error path leaves stale stackref that `_PyFrame_ClearLocals` over-decrefs · Issue #152147 · python/cpython · GitHub

Open Graph Title: Use-after-free under MemoryError: opcode error path leaves stale stackref that `_PyFrame_ClearLocals` over-decrefs · Issue #152147 · python/cpython

X Title: Use-after-free under MemoryError: opcode error path leaves stale stackref that `_PyFrame_ClearLocals` over-decrefs · Issue #152147 · python/cpython

Description: Crash report What happened? (OOM-0005 in #151763) When an allocation fails (MemoryError) partway through a bytecode instruction, the eval loop unwinds the frame through exit_unwind, clearing the operand stack via _PyFrame_ClearLocals() (...

Open Graph Description: Crash report What happened? (OOM-0005 in #151763) When an allocation fails (MemoryError) partway through a bytecode instruction, the eval loop unwinds the frame through exit_unwind, clearing the op...

X Description: Crash report What happened? (OOM-0005 in #151763) When an allocation fails (MemoryError) partway through a bytecode instruction, the eval loop unwinds the frame through exit_unwind, clearing the op...

Opengraph URL: https://github.com/python/cpython/issues/152147

X: @github

direct link

Domain: github.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Use-after-free under MemoryError: opcode error path leaves stale stackref that `_PyFrame_ClearLocals` over-decrefs","articleBody":"# Crash report\n\n### What happened?\n\n([OOM-0005](https://gist.github.com/devdanzin/22b71f61343c81df5bea9b7fca798e87) in https://github.com/python/cpython/issues/151763)\n\nWhen an allocation fails (`MemoryError`) partway through a bytecode instruction, the eval loop unwinds the frame through `exit_unwind`, clearing the operand stack via `_PyFrame_ClearLocals()` (`Python/frame.c:101`), which `PyStackRef_XCLOSE`s every live stack slot. If an opcode's allocation-failure error path has left a **stale / over-counted** `_PyStackRef` on the value stack — a value it already consumed/stole, or a borrowed reference it doesn't own — that close drops the object's refcount below what it should be. When the object is **also referenced elsewhere**, it is freed while still live → **use-after-free** (on a plain debug build the same over-decref is caught earlier as a `_Py_NegativeRefcount` abort).\n\nThis is reachable through ordinary stdlib code, with no `ctypes`/`_testcapi`-constructed objects — only `_testcapi.set_nomemory` to drive the allocation failure.\n\n## Reproducer\n\nDeterministic (≥5/5) on debug + ASan builds (both free-threaded and GIL); requires a debug build exposing `_testcapi.set_nomemory`:\n\n```python\nimport pkgutil\nimport faulthandler\nfaulthandler.enable()\nfrom _testcapi import set_nomemory\n\nd = {\"s\": str}\nd[\"arg\"] = d[\"s\"](0)            # a heap str (\"0\"), also kept alive by this dict\n\ndef sweep(thunk):\n    for start in range(60):\n        set_nomemory(start)     # fail every allocation from #start onward\n        try:\n            thunk()\n        except BaseException:\n            pass\n\ndef call_get_importer():\n    pkgutil.get_importer(d[\"arg\"])   # -\u003e os.fsdecode -\u003e os.fspath; the arg is freed mid-unwind\n\nsweep(call_get_importer)\n```\n\nThe nested-frame structure (the `sweep(thunk)` wrapper) matters — a flat module-level loop does not reproduce.\n\n## What happens\n\nOn a **debug GIL + ASan** build, ASan reports a clean heap-use-after-free; the freed `str` argument is read after it was freed during the unwind:\n\n```\nERROR: AddressSanitizer: heap-use-after-free  Include/refcount.h:286 in Py_INCREF\n\nFREED by (the over-decref — the bug):\n  #4 PyStackRef_XCLOSE        Include/internal/pycore_stackref.h:726\n  #5 _PyFrame_ClearLocals     Python/frame.c:101            \u003c- closes a stale operand-stack slot\n  #6 _PyFrame_ClearExceptCode Python/frame.c:126\n  #7 clear_thread_frame       Python/ceval.c:1954\n  #8 _PyEval_EvalFrameDefault Python/generated_cases.c.h    (exit_unwind)\n\nREAD of freed memory (later use of the same str):\n  #0 Py_INCREF                Include/refcount.h:286\n  #3 _Py_dict_lookup_threadsafe Objects/dictobject.c:1729   (the dict still holds the string)\n\nPREVIOUSLY ALLOCATED (victim = str(0), \"0\"):\n  #4 PyUnicode_New            Objects/unicodeobject.c:1326\n  #7 PyObject_Str             Objects/object.c:826\n```\n\nOn a **debug free-threaded + ASan** build the same freed local is instead read by `PyOS_FSPath` (`Modules/posixmodule.c:17168`) → `PyType_HasFeature` on `Py_TYPE(path)` (`ob_type == 0xdd`) → SIGSEGV. Which downstream *use* faults depends on build/timing; the defect is the single over-decref.\n\n## Analysis\n\n`_PyFrame_ClearLocals` is correct only if `frame-\u003estackpointer` accurately reflects the slots the frame still owns:\n\n```c\nwhile (sp \u003e locals) {\n    sp--;\n    PyStackRef_XCLOSE(*sp);   /* frame.c:101 */\n}\n```\n\nThe defect is **upstream**: an opcode that can fail under allocation pressure took an error exit after consuming/stealing a stack value (or after pushing a borrowed reference) without removing that slot from the stack pointer; the dead/over-counted `_PyStackRef` is then closed during the unwind. Reverse-execution (`rr`) of the reproducer shows the freed `str` is referenced by the holding dict, several call frames, the raised `OSError`'s fields, and an args tuple, and the OOM-unwind dealloc cascade decrefs it one time too many; I was not able to isolate the single offending opcode to one source line.\n\nThis appears to be a distinct instance of the general \"OOM error path leaves a stale stackref on the value stack\" class. It is **not** the specialized `_CALL_LIST_APPEND` `list.append` double-free (gh-151818) — the reproducer here involves no `list.append` (rr-confirmed) — though it is the same family as the `LIST_APPEND` stack-pointer-sync issue (gh-151119 / PR gh-151538), which fixes one specific opcode.\n\n## Suggested fix\n\nAudit bytecode-handler error/cleanup paths (and the generated `pop_N_error:` / `error:` stubs in `Python/bytecodes.c` / `generated_cases.c.h`) so that on any allocation-failure exit, `frame-\u003estackpointer` exactly matches the set of still-owned stackrefs. The fix belongs in the opcode that leaks the stale reference, not in `_PyFrame_ClearLocals` (which must trust the stack pointer). As a debugging aid, the stack-effect invariants could be asserted on the error path before `_PyEval_FrameClearAndPop`.\n\n## Versions\n\nReproduces on debug builds (free-threaded and GIL, ± ASan); on release builds the negative-refcount assert is compiled out and the use-after-free is latent. Likely long-standing in the stackref eval loop.\n\n## Notes\n\nFound via OOM-injection fuzzing (`_testcapi.set_nomemory`). Part of #151763. Full write-up, reproducer, and backtraces: https://gist.github.com/devdanzin/22b71f61343c81df5bea9b7fca798e87\n\n_(Investigation and draft assisted by Claude Code.)_\n\n\n### CPython versions tested on:\n\nCPython main branch\n\n### Operating systems tested on:\n\nLinux\n\n### Output from running 'python -VV' on the command line:\n\nPython 3.16.0a0 (heads/main:1b9fe5c7226, Jun 20 2026, 23:31:55) [Clang 21.1.8 (6ubuntu1)]","author":{"url":"https://github.com/devdanzin","@type":"Person","name":"devdanzin"},"datePublished":"2026-06-25T02:53:14.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":1},"url":"https://github.com/152147/cpython/issues/152147"}

route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:fff26481-bb3d-5a28-0a4e-afc57a03cb9f
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-idD4EC:15F1A6:18ECBF6:21550D0:6A535795
html-safe-noncede27cefec0d0df59e46a153d02d20dcfd84efde56273e7e564d6a2095b26d525
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJENEVDOjE1RjFBNjoxOEVDQkY2OjIxNTUwRDA6NkE1MzU3OTUiLCJ2aXNpdG9yX2lkIjoiNjYzNTk0NTYxMzM3OTk4MzI1MyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9
visitor-hmace13b5a07b58e95b72accea82f841e7a59ce411d07f4e67cbeceb8769a351880b
hovercard-subject-tagissue:4740183924
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/152147/issue_layout
twitter:imagehttps://opengraph.githubassets.com/7be631ed65d91f6a9796b276ef275a21899ac712d29597728b72438f415a0e2b/python/cpython/issues/152147
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/7be631ed65d91f6a9796b276ef275a21899ac712d29597728b72438f415a0e2b/python/cpython/issues/152147
og:image:altCrash report What happened? (OOM-0005 in #151763) When an allocation fails (MemoryError) partway through a bytecode instruction, the eval loop unwinds the frame through exit_unwind, clearing the op...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernamedevdanzin
hostnamegithub.com
expected-hostnamegithub.com
Noneb9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb
turbo-cache-controlno-preview
go-importgithub.com/python/cpython git https://github.com/python/cpython.git
octolytics-dimension-user_id1525981
octolytics-dimension-user_loginpython
octolytics-dimension-repository_id81598961
octolytics-dimension-repository_nwopython/cpython
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id81598961
octolytics-dimension-repository_network_root_nwopython/cpython
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release07a982c1d40157c619b364352b704c3ce66bb332
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://github.com/python/cpython/issues/152147#start-of-content
https://github.com/
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython%2Fcpython%2Fissues%2F152147
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub Copilot appDirect agents from issue to mergehttps://github.com/features/ai/github-app
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
View all resourceshttps://github.com/resources
GitHub SponsorsFund open source developershttps://github.com/open-source/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/open-source/accelerator
GitHub Starshttps://stars.github.com
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/enterprise/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython%2Fcpython%2Fissues%2F152147
Sign up https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=python%2Fcpython
Reloadhttps://github.com/python/cpython/issues/152147
Reloadhttps://github.com/python/cpython/issues/152147
Reloadhttps://github.com/python/cpython/issues/152147
Please reload this pagehttps://github.com/python/cpython/issues/152147
python https://github.com/python
cpythonhttps://github.com/python/cpython
Please reload this pagehttps://github.com/python/cpython/issues/152147
Notifications https://github.com/login?return_to=%2Fpython%2Fcpython
Fork 35k https://github.com/login?return_to=%2Fpython%2Fcpython
Star 73.8k https://github.com/login?return_to=%2Fpython%2Fcpython
Code https://github.com/python/cpython
Issues 5k+ https://github.com/python/cpython/issues
Pull requests 2.3k https://github.com/python/cpython/pulls
Actions https://github.com/python/cpython/actions
Projects https://github.com/python/cpython/projects
Security and quality 0 https://github.com/python/cpython/security
Insights https://github.com/python/cpython/pulse
Code https://github.com/python/cpython
Issues https://github.com/python/cpython/issues
Pull requests https://github.com/python/cpython/pulls
Actions https://github.com/python/cpython/actions
Projects https://github.com/python/cpython/projects
Security and quality https://github.com/python/cpython/security
Insights https://github.com/python/cpython/pulse
#151818https://github.com/python/cpython/issues/151818
#151818https://github.com/python/cpython/issues/151818
Use-after-free under MemoryError: opcode error path leaves stale stackref that _PyFrame_ClearLocals over-decrefshttps://github.com/python/cpython/issues/152147#top
interpreter-core(Objects, Python, Grammar, and Parser dirs)https://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22interpreter-core%22
type-crashA hard crash of the interpreter, possibly with a core dumphttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22type-crash%22
https://github.com/devdanzin
devdanzinhttps://github.com/devdanzin
on Jun 25, 2026https://github.com/python/cpython/issues/152147#issue-4740183924
OOM-0005https://gist.github.com/devdanzin/22b71f61343c81df5bea9b7fca798e87
#151763https://github.com/python/cpython/issues/151763
gh-151818https://github.com/python/cpython/issues/151818
gh-151119https://github.com/python/cpython/issues/151119
gh-151538https://github.com/python/cpython/pull/151538
#151763https://github.com/python/cpython/issues/151763
https://gist.github.com/devdanzin/22b71f61343c81df5bea9b7fca798e87https://gist.github.com/devdanzin/22b71f61343c81df5bea9b7fca798e87
interpreter-core(Objects, Python, Grammar, and Parser dirs)https://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22interpreter-core%22
type-crashA hard crash of the interpreter, possibly with a core dumphttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22type-crash%22
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.