Title: ceval: CALL_LIST_APPEND bytecode leaves a dangling stack reference on the stack on error · Issue #152090 · python/cpython · GitHub
Open Graph Title: ceval: CALL_LIST_APPEND bytecode leaves a dangling stack reference on the stack on error · Issue #152090 · python/cpython
X Title: ceval: CALL_LIST_APPEND bytecode leaves a dangling stack reference on the stack on error · Issue #152090 · python/cpython
Description: Bug report Script bug.py (from issue gh-149146, but modified): import resource import signal import os def segfault_handler(signum, frame): os.abort() raise MemoryError #signal.signal(signal.SIGSEGV, segfault_handler) # deallocation the ...
Open Graph Description: Bug report Script bug.py (from issue gh-149146, but modified): import resource import signal import os def segfault_handler(signum, frame): os.abort() raise MemoryError #signal.signal(signal.SIGSEG...
X Description: Bug report Script bug.py (from issue gh-149146, but modified): import resource import signal import os def segfault_handler(signum, frame): os.abort() raise MemoryError #signal.signal(signal.SIGSEG...
Opengraph URL: https://github.com/python/cpython/issues/152090
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"ceval: CALL_LIST_APPEND bytecode leaves a dangling stack reference on the stack on error","articleBody":"# Bug report\n\nScript `bug.py` (from issue gh-149146, but modified):\n\n```py\nimport resource\nimport signal\nimport os\n\ndef segfault_handler(signum, frame):\n os.abort()\n raise MemoryError\n\n#signal.signal(signal.SIGSEGV, segfault_handler)\n\n# deallocation the chain uses a lot of C stack memory\nCHAIN_LENGTH = 1024 * 1024\n\n# limit process memory to not crash the whole machine\nmax_memory = 1024 * 1024 * 1024\nresource.setrlimit(resource.RLIMIT_AS, (max_memory, max_memory))\n\nprint(\"create long chain...\")\nlong_chain = None\nfor _ in range(CHAIN_LENGTH):\n long_chain = (long_chain, None)\n\nprint(\"fill the process memory...\")\n\nmemory = []\ntry:\n large = 1024 * 1024\n while True:\n memory.append(b'x' * large)\nexcept MemoryError:\n pass\n\ntry:\n small = 1024\n os.uname()\n while True:\n memory.append(b'x' * small)\nexcept MemoryError:\n pass\n\nprint(\"delete the long chain...\")\nlong_chain = None\n\n# at exit (on error), deallocating long_chain will use a lot of C stack memory\n# ... and does crash!\n```\n\nSometimes, running this script triggers a bug when `memory.append(b'x' * small)` raises a `MemoryError`. Sadly, the reproducer is very fragile. So far, I failed to write a more reliable reproducer.\n\nThe fix is to set `stack_pointer[-1]` to `PyStackRef_NULL` in `_CALL_LIST_APPEND` before calling `JUMP_TO_LABEL(error);`.\n\nSteps:\n\n* PyErr_NoMemory() is called by _PyList_AppendTakeRefListResize() in `_CALL_LIST_APPEND` opcode\n* At this point, `stack_pointer[-1]` (`arg`) points to freed memory (all bytes are set to `0xdd`)\n* `_PyList_AppendTakeRef()` returns non-zero result, so `_CALL_LIST_APPEND` opcode goes to `JUMP_TO_LABEL(error);`\n* The `error` label calls `JUMP_TO_LABEL(exception_unwind);`\n* `exception_unwind` label clears the stack: call `ref = _PyFrame_StackPop()` and `PyStackRef_XCLOSE(ref)` until the stack is empty\n* `exception_unwind`: `PyStackRef_XCLOSE(ref)` fails with an assertion error (`Py_DECREF_MORTAL: Assertion `!_Py_IsStaticImmortal(op)'`) because `stack_pointer[-1]` points to freed memory\n\n```\n$ gdb -args ./python bug.py \n(gdb) b os_uname\n(gdb) run\n\nBreakpoint 2, os_uname (...)\n(gdb) b PyErr_NoMemory\n(gdb) c\nContinuing.\n\nBreakpoint 3, PyErr_NoMemory () at Python/errors.c:803\n803\t{\n(gdb) n\n(...)\n\n(gdb) \n_PyList_AppendTakeRefListResize (...)\n531\t Py_DECREF(newitem);\n(gdb) \n532\t return -1;\n\n(gdb) \n_PyEval_EvalFrameDefault (tstate=\u003coptimized out\u003e, frame=0x7ffff7fb0020, throwflag=0) at Python/generated_cases.c.h:3983\n3983\t if (err) {\n(gdb) p stack_pointer[-1]\n$2 = \u003cunknown at remote 0xcc08e0\u003e\n(gdb) p /x *(PyObject*)stack_pointer[-1]\n$3 = {\n {\n ob_refcnt_full = 0xdddddddddddddddd,\n {\n ob_refcnt = 0xdddddddd,\n ob_overflow = 0xdddd,\n ob_flags = 0xdddd\n },\n _aligner = 0xdd\n },\n ob_type = 0xdddddddddddddddd\n}\n(gdb) n\n3984\t JUMP_TO_LABEL(error);\n\n(gdb) n\n(...)\n(gdb) \n13843\t JUMP_TO_LABEL(exception_unwind);\n\n(gdb) \n13849\t int offset = INSTR_OFFSET()-1;\n(...)\n(gdb) \n13865\t while (frame-\u003estackpointer \u003e new_top) {\n(gdb) \n13866\t _PyStackRef ref = _PyFrame_StackPop(frame);\n(gdb) \n13867\t PyStackRef_XCLOSE(ref);\n(gdb) p ref\n$5 = \u003cunknown at remote 0xcc08e0\u003e\n(gdb) p /x *(PyObject*)ref\n$6 = {\n {\n ob_refcnt_full = 0xdddddddddddddddd,\n {\n ob_refcnt = 0xdddddddd,\n ob_overflow = 0xdddd,\n ob_flags = 0xdddd\n },\n _aligner = 0xdd\n },\n ob_type = 0xdddddddddddddddd\n}\n(gdb) n\npython: ./Include/internal/pycore_object.h:414: Py_DECREF_MORTAL: Assertion `!_Py_IsStaticImmortal(op)' failed.\n\nProgram received signal SIGABRT, Aborted.\n0x00007ffff7cfedcc in __pthread_kill_implementation () from /lib64/libc.so.6\n```\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-152091\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/vstinner","@type":"Person","name":"vstinner"},"datePublished":"2026-06-24T15:32:15.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/152090/cpython/issues/152090"}
| 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:aa703ac9-3d4b-8d7f-26a8-d04b0fc7dbb4 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 8DFE:19106:169A750:1ED91A6:6A53E0AE |
| html-safe-nonce | be0cbd1381fa2ec75ba9198d1303082aafcc81766abf5feaf89da370f1b17613 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4REZFOjE5MTA2OjE2OUE3NTA6MUVEOTFBNjo2QTUzRTBBRSIsInZpc2l0b3JfaWQiOiI3MjA2NDgyOTYxNTM3MTYzNDM4IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | ec7132cda0f7ecd0629651a8c8a7daccf00fd29f7ac5f22032586cae621c2f56 |
| hovercard-subject-tag | issue:4736229254 |
| 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/152090/issue_layout |
| twitter:image | https://opengraph.githubassets.com/224809efb53299243368bc7cfc76116d7ce03b774d2f82b1c211cba257595c95/python/cpython/issues/152090 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/224809efb53299243368bc7cfc76116d7ce03b774d2f82b1c211cba257595c95/python/cpython/issues/152090 |
| og:image:alt | Bug report Script bug.py (from issue gh-149146, but modified): import resource import signal import os def segfault_handler(signum, frame): os.abort() raise MemoryError #signal.signal(signal.SIGSEG... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | vstinner |
| 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