Title: CPython crashes on memory-allocation failure (OOM): 35 findings (4 dups → 31 distinct) · Issue #151763 · python/cpython · GitHub
Open Graph Title: CPython crashes on memory-allocation failure (OOM): 35 findings (4 dups → 31 distinct) · Issue #151763 · python/cpython
X Title: CPython crashes on memory-allocation failure (OOM): 35 findings (4 dups → 31 distinct) · Issue #151763 · python/cpython
Description: Crash report What happened? Allocation-failure fuzzing of CPython main turned up 35 distinct ways the interpreter crashes — segfault, failed assert(...), or Py_FatalError — when a memory allocation (4 have since been confirmed as duplica...
Open Graph Description: Crash report What happened? Allocation-failure fuzzing of CPython main turned up 35 distinct ways the interpreter crashes — segfault, failed assert(...), or Py_FatalError — when a memory allocation...
X Description: Crash report What happened? Allocation-failure fuzzing of CPython main turned up 35 distinct ways the interpreter crashes — segfault, failed assert(...), or Py_FatalError — when a memory allocation...
Opengraph URL: https://github.com/python/cpython/issues/151763
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"CPython crashes on memory-allocation failure (OOM): 35 findings (4 dups → 31 distinct)","articleBody":"# Crash report\n\n### What happened?\n\nAllocation-failure fuzzing of CPython `main` turned up **35 distinct ways the interpreter\ncrashes** — segfault, failed `assert(...)`, or `Py_FatalError` — when a memory allocation (4 have since been confirmed as duplicates via `rr` → 31 distinct; see the dedup comment)\nfails part-way through an operation. Each is a separate underlying bug with a minimal,\nstdlib-only reproducer, a backtrace, a root-cause analysis, and a suggested fix, published\nas a self-contained gist (linked below).\n\nI'm filing them under one umbrella so they can be picked off individually without flooding\nthe tracker with 35 issues at once. **To take one:** open a normal CPython issue (or PR) for\nit and drop a comment here with the link — I'll mark it in the table. If any turn out to be\nduplicates or non-bugs, say so and I'll annotate them.\n\nThese were found with [fusil](https://github.com/devdanzin/fusil)'s OOM-injection mode\n(fusil originally by @vstinner). The reports and reduced reproducers were drafted with\nAI assistance (Claude Code) and then reviewed and re-verified by hand — see *Disclosure*.\n\n## Reproducing\n\n- Found on `main` (3.16.0a0) at commit `15d7406`. These are allocation-path bugs, so they\n are not tied to that exact revision.\n- Every gist ships a minimal `OOM-ID-repro.py` (standard library only) that drives the failing path\n while `_testcapi.set_nomemory(...)` forces allocations to fail. Just run **`python\n OOM-ID-repro.py`** — where the exact failing-allocation index is sensitive to the build's\n allocation count, the repro *self-sweeps* (a fresh subprocess per index) and stops at the\n first crash, so no manual tuning is needed.\n- `_testcapi.set_nomemory` requires a test/debug interpreter (`--with-pydebug` exposes it).\n- **Build matrix** (in each report): many of these are debug-only assertion / `Py_FatalError`\n failures — the `assert(...)` is compiled out under `-DNDEBUG`, so a *release* build doesn't\n abort. They are still real bugs: on release the same defect is latent undefined behaviour\n (a use-after-free, a `Py_DECREF(NULL)`, or a silently-lost exception). A subset segfault on\n release builds directly; those are called out below.\n\n## Highest-confidence starting points\n\nThese crash a **release** build (not just a debug assertion) **and** have a clean minimal\nreproducer — the lowest-effort to confirm and fix:\n\n- **OOM-0034**, **OOM-0028** — unchecked `PyUnicode_AsUTF8` / `PyUnicode_EncodeFSDefault`\n returning `NULL` is dereferenced (≈ one-line NULL checks).\n- **OOM-0001**, **OOM-0002**, **OOM-0014** — `Py_DECREF(NULL)` on an unchecked-allocation\n error path.\n- **OOM-0031** — `_interpreters.capture_exception` calls `_PyXI_FreeExcInfo(NULL)` with no\n NULL guard.\n- **OOM-0012**, **OOM-0020** — instrumentation / thread-state corruption under OOM.\n\n## Findings\n\nStatus: blank = not yet filed · `#N` = a CPython issue is open · 🔁 = **confirmed duplicate, folded into another finding — please don't pursue**.\n\n### Segfaults (7)\n\n| Report | Title | Status |\n|---|---|---|\n| [OOM-0001](https://gist.github.com/devdanzin/464cef74ca8186843f33a38078476ac4) | Segfault: `Py_DECREF` of a NULL `filename` in `do_warn` (`_warnings.c:1139`) | [#151673](https://github.com/python/cpython/issues/151673) |\n| [OOM-0002](https://gist.github.com/devdanzin/2dfeabe7508f8e98f27f6df7e381f1cf) | Segfault: `Py_DECREF(NULL)` in `PyContextVar_Set` (`context.c:367`) | |\n| [OOM-0024](https://gist.github.com/devdanzin/acf15ad4117c6343b48ed8fdfe7ad167) | Segfault: dealloc of uninitialized iterator in `template_iter` (`templateobject.c:232`) |#151815 |\n| [OOM-0028](https://gist.github.com/devdanzin/774867b89b3de8d36d7e2ac405034577) | Segfault: NULL deref in `os__path_normpath_impl` (`posixmodule.c:6149`) | |\n| [OOM-0031](https://gist.github.com/devdanzin/44ffdf25538575e497fd80552ea5d467) | Segfault: NULL `info` deref in `_excinfo_clear_type` (`crossinterp.c:1319`) | #152013 |\n| [OOM-0033](https://gist.github.com/devdanzin/249032e1746d63406a5f68d7dfdedb79) | [SUPERSEDED — duplicate of OOM-0036 / #151818] Segfault / negative-refcount: over-decreffed `sys.path` entry in `PyType_IsSubtype` (`typeobject.c:2931`) | 🔁 dup of OOM-0036 → [#151818](https://github.com/python/cpython/issues/151818) |\n| [OOM-0034](https://gist.github.com/devdanzin/9871a21facf4c9c6a415e220f9d10762) | Segfault: unchecked `PyUnicode_AsUTF8` NULL deref in `pegen.c:33` | #151798 |\n\n### Assertion failures / aborts (23)\n\n| Report | Title | Status |\n|---|---|---|\n| [OOM-0003](https://gist.github.com/devdanzin/b628c59722820b55c61a400a973771d5) | Abort: uninitialized `_co_unique_id` assert in `code_dealloc` (`codeobject.c:2440`) | #152034 |\n| [OOM-0004](https://gist.github.com/devdanzin/315e83b2da6a5809ce5ae1d748cdd0ae) | Abort/Segfault: corrupted object freelist in `clear_freelist` (`object.c:909`) | |\n| [OOM-0005](https://gist.github.com/devdanzin/22b71f61343c81df5bea9b7fca798e87) | [SUPERSEDED — duplicate of OOM-0036 / #151818] Abort: negative-refcount over-decref in `_PyFrame_ClearLocals` (`frame.c:101`) | 🔁 dup of OOM-0036 → [#151818](https://github.com/python/cpython/issues/151818) |\n| [OOM-0006](https://gist.github.com/devdanzin/c809eb4072c0c787c0c890f54ba1c843) | Abort/Segfault: `_PyObject_GC_UNTRACK` assert on untracked iterator in `dictiter_dealloc` (`dictobject.c:5532`) | |\n| [OOM-0008](https://gist.github.com/devdanzin/3c6690d0561acc62752a953e12b20197) | Abort: `assert(!PyErr_Occurred())` in `_PyType_LookupStackRefAndVersion` (`typeobject.c:6343`) | |\n| [OOM-0009](https://gist.github.com/devdanzin/34b633230f6d2301ba17dec195ffe4b7) | Abort: stale `release1` flag trips an ownership assert in `replace` (`unicodeobject.c:10783`) | #152228 |\n| [OOM-0010](https://gist.github.com/devdanzin/d3c1d06e95c006a320dbbfffcc210d52) | Abort: `assert(_PyErr_Occurred(tstate))` in `_PyEval_EvalFrameDefault` (`generated_cases.c.h:13817`) | |\n| [OOM-0011](https://gist.github.com/devdanzin/892b61619c1b3c8c2018331b3f1f4983) | [SUPERSEDED — duplicate of OOM-0008] Abort: `assert(!PyErr_Occurred())` in `specialize` (`specialize.c:364`) | 🔁 dup of OOM-0008 (above) |\n| [OOM-0012](https://gist.github.com/devdanzin/610c147c8e2d42a576bab3c1c2713391) | Abort/Segfault: stale instrumentation in `get_tools_for_instruction` (`instrumentation.c:1106`) | |\n| [OOM-0013](https://gist.github.com/devdanzin/1736971107bea3aa04ce19db21c90845) | Abort: builtin breaks result/error contract in `_Py_BuiltinCallFastWithKeywords_StackRef` (`ceval.c:843`) | |\n| [OOM-0014](https://gist.github.com/devdanzin/ceb4b16662d22b3dcb1b56cd8481c9e7) | Abort/Segfault: unchecked NULL in `channelsmod__channel_id` (`_interpchannelsmodule.c:3487`) | |\n| [OOM-0015](https://gist.github.com/devdanzin/d40d39e6abfb746bd9d96de261205190) | Abort: stale exception in `cfunction_check_kwargs` (`methodobject.c:409`) | |\n| [OOM-0016](https://gist.github.com/devdanzin/05be8efe6b08c2b3ac3e2c17c784da0c) | Abort: `assert(!queue-\u003ealive)` in `_queue_clear` (`_interpqueuesmodule.c:559`) | #152130 |\n| [OOM-0017](https://gist.github.com/devdanzin/6e7a3a9487689e55d7dd4f70b1ce489f) | Abort: negative `gc_refs` (\"refcount too small\") in `validate_gc_objects` (`gc_free_threading.c:1116`) | |\n| [OOM-0018](https://gist.github.com/devdanzin/99b84915b197ae0ade7face262b8af66) | Abort: ownership assert in `set_keys` (`dictobject.c:205`) | #152254 |\n| [OOM-0019](https://gist.github.com/devdanzin/9bd9423256ea03c08231d1ebe542db89) | Abort: double-free in `_PyPegen_raise_error_known_location` (`pegen_errors.c:363`) | |\n| [OOM-0025](https://gist.github.com/devdanzin/3aaffc18b68ca2ae5fffa72aa6cdb2ea) | Abort: `assert(!PyErr_Occurred())` in `unspecialize` (`specialize.c:378`) | |\n| [OOM-0026](https://gist.github.com/devdanzin/bf6f784d4bcd21acd471ea45b6f23c70) | Abort: err-code vs `PyErr` desync in `handle_channel_error` (`_interpchannelsmodule.c:398` / `:443`) | #152156 |\n| [OOM-0027](https://gist.github.com/devdanzin/d5c602c29ac3881290269b444d77db3c) | Abort: `assert(PyStackRef_BoolCheck(cond))` in `POP_JUMP_IF_FALSE` (`generated_cases.c.h:11120`) | |\n| [OOM-0029](https://gist.github.com/devdanzin/10e0fdaf3d89dbe394d94fbf765c70a1) | [SUPERSEDED — duplicate of OOM-0036 / #151818] Abort: negative refcount on a `MemoryError` (`tuple_dealloc`, `tupleobject.c:277`) | 🔁 dup of OOM-0036 → [#151818](https://github.com/python/cpython/issues/151818) |\n| [OOM-0030](https://gist.github.com/devdanzin/fbfb9d6cd5eeb518e4f9eeab44be3893) | Abort: `Py_DECREF` of NULL-data unicode in `unicode_subtype_new` (`unicodeobject.c:13986`) | |\n| [OOM-0032](https://gist.github.com/devdanzin/f7e483080647c7b76fbda79bfeb07e9c) | Abort: pending-exception assert from `warn_explicit` normalization (`_warnings.c:799/806`) | |\n| [OOM-0035](https://gist.github.com/devdanzin/8c86ca358f3711740a692eaac730b527) | Abort / malformed str: invalid `maxchar` in `_PyUnicode_FromUCS4` (`unicodeobject.c:2228`) | |\n\n### Fatal Python error (5)\n\n| Report | Title | Status |\n|---|---|---|\n| [OOM-0007](https://gist.github.com/devdanzin/bf9fec4554c58c2a279b05b7ff8e6d9b) | Fatal: `context_tp_dealloc` clears the pending exception (`context.c:535`) | #152083 |\n| [OOM-0020](https://gist.github.com/devdanzin/df523c79368baa0c44bd69e9d5ee0c7e) | Fatal: `_PyMem_DebugRawFree: bad ID` in `free_threadstate` (`pystate.c:1527`) | |\n| [OOM-0021](https://gist.github.com/devdanzin/e113c48a4e249ae7e4d1e42020db65c4) | Fatal: NULL returned without an exception set in `_Py_CheckFunctionResult` (`call.c:43`) | |\n| [OOM-0022](https://gist.github.com/devdanzin/0964a71a7038ee90137f11c2527aad3c) | Fatal: stale `MemoryError` trips `_Py_CheckSlotResult` in `reload_singlephase_extension` (`import.c:2011`) | |\n| [OOM-0023](https://gist.github.com/devdanzin/dc5123e50ea0402292e841411a294d3d) | Fatal: dealloc clears the in-flight exception in `subtype_dealloc` (`typeobject.c:2719`) | |\n\n## Related groups (one fix may cover several)\n\n- **Dealloc clears the in-flight exception** (the gh-89373 `_Py_Dealloc` invariant): **OOM-0007**\n (`context_tp_dealloc`) and **OOM-0023** (the generic `subtype_dealloc`, covering a family of\n pure-Python types) free an object while a `MemoryError` is pending and don't save/restore it.\n- **A pending exception survives into code that asserts there is none** (specializer / eval /\n call layers): **OOM-0008, 0010, 0015, 0025, 0032** (OOM-0011 was a second detector face of\n OOM-0008 — same `frame.f_back` swallow — and is folded). Several share the theme that the\n adaptive specializer / call machinery is entered with a `MemoryError` already pending.\n- **`Py_DECREF`/`Py_CLEAR` of a NULL or partially-initialized object on the OOM error path:**\n **OOM-0001, 0002, 0006, 0014, 0024, 0030, 0031** (an allocation fails after a slot is taken\n but before the object is valid, and the error path frees it anyway).\n- **Over-decref → negative refcount under OOM** (a real memory-safety bug; the assert is the\n debug-build detector): **OOM-0019**. *(rr later showed OOM-0005, OOM-0029 and OOM-0033 are\n all the same `_CALL_LIST_APPEND` `list.append()`-under-`MemoryError` double-free —\n **OOM-0036, filed [#151818](https://github.com/python/cpython/issues/151818)** — and are\n folded; OOM-0019 is a distinct pegen double-free.)*\n- **Free-threading-specific:** **OOM-0003** (`_co_unique_id`), **OOM-0017** (cyclic GC),\n **OOM-0018** (managed dict), **OOM-0020** (thread-state reservation).\n\n## Disclosure \u0026 caveats\n\n- The reports and reduced reproducers were **drafted with AI assistance (Claude Code)**; each\n gist carries an explicit disclaimer. The reproducers were re-run on the build matrix and the\n root causes audited against the CPython source before publishing.\n- A few root causes are explicitly marked **partial** — the trigger is minimal and verified,\n but the exact offending line wasn't pinned (noted in those reports): OOM-0010, 0027, 0035.\n- **OOM-0001** is already filed as\n [#151673](https://github.com/python/cpython/issues/151673); the other 34 had no matching\n python/cpython issue when checked and appear novel.\n\n---\n\n*Found with [fusil](https://github.com/devdanzin/fusil) (OOM-injection mode; fusil originally\nby Victor Stinner). Drafted with Claude Code; reproducers machine-generated and human-verified.*\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 free-threading build (heads/main:15d74068f3a, Jun 18 2026, 16:44:30) [Clang 22.1.2 (1ubuntu1)]\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-151779\n* gh-151798\n* gh-151902\n* gh-151931\n* gh-151968\n* gh-152013\n* gh-152034\n* gh-152069\n* gh-152070\n* gh-152094\n* gh-152095\n* gh-152096\n* gh-152131\n* gh-152155\n* gh-152158\n* gh-152159\n* gh-152160\n* gh-152164\n* gh-152165\n* gh-152836\n* gh-152837\n* gh-152840\n* gh-153548\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/devdanzin","@type":"Person","name":"devdanzin"},"datePublished":"2026-06-20T00:55:43.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":18},"url":"https://github.com/151763/cpython/issues/151763"}
| 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:da072ea3-3bd6-f7a0-6dd9-8ac8ff92f815 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8696:101E6F:5413F:6F968:6A5251AC |
| html-safe-nonce | 9e818d8853f085a76d8b28801abeb140f8e479fceaba9e3ed457cb41b429ac68 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4Njk2OjEwMUU2Rjo1NDEzRjo2Rjk2ODo2QTUyNTFBQyIsInZpc2l0b3JfaWQiOiIzNjk5ODgyNjk1NDA2NTM5MTgwIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | cecf6b50c501a9a4fc6b4887eb0f79eef164edc1279d515e0f3cf94d49a50b25 |
| hovercard-subject-tag | issue:4704484084 |
| 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/151763/issue_layout |
| twitter:image | https://opengraph.githubassets.com/1e6ee38db341e73938d432103fa092235035dd702f5a8007afe3d8cd2c63a3bc/python/cpython/issues/151763 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/1e6ee38db341e73938d432103fa092235035dd702f5a8007afe3d8cd2c63a3bc/python/cpython/issues/151763 |
| og:image:alt | Crash report What happened? Allocation-failure fuzzing of CPython main turned up 35 distinct ways the interpreter crashes — segfault, failed assert(...), or Py_FatalError — when a memory allocation... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | devdanzin |
| 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 | 7aed05249554b889eb33d002851a973eebcc7e91 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width