python / python/cpython

Segfault: `Py_DECREF(NULL)` in `setup_context`/`do_warn` (`_warnings.c`) when emitting a warning under MemoryError

未關閉
#151,673 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

extension-modules type-crash
主要語言
Python
星號
77.2k
分支
36k
PR 合併指標
PR 指標待擷取

描述

Crash report

What happened?

AI Disclaimer: this issue was drafted by Claude Code, which also generated the reduced reproducer.

Emitting a warning while allocations are failing segfaults on a Py_DECREF of a NULL filename. setup_context() does not NULL-check PyUnicode_FromString("<sys>"), and the resulting NULL is later decref'd either by do_warn() (success path) or by setup_context()'s own handle_error: label (which uses Py_DECREF, not Py_XDECREF).

Reproducer

import _testcapi, warnings, faulthandler
faulthandler.enable()
warnings.simplefilter("always")
_testcapi.set_nomemory(0, 0)   # fail every allocation from here on
warnings.warn("boom")          # -> Py_DECREF(NULL) -> SIGSEGV

Deterministic (start=0). Reproduced on main.

Backtrace

#0 _Py_atomic_load_uint32_relaxed   Include/cpython/pyatomic_gcc.h
#1 Py_DECREF                        Include/refcount.h
#2 do_warn                          Python/_warnings.c:1139   <- Py_DECREF(filename), filename == NULL
#3 warnings_warn_impl               Python/_warnings.c:1184
#4 warnings_warn                    Python/clinic/_warnings.c.h:161

(gdb) frame 2; print filename$1 = (PyObject *) 0x0.

Root cause

In setup_context() (_warnings.c), the f == NULL branch (~L1036):

if (f == NULL) {
    globals = interp->sysdict;
    *filename = PyUnicode_FromString("<sys>");   /* return value unchecked */
    *lineno = 0;
}

Under memory pressure two allocations fail in sequence:

  1. PyThreadState_GetFrame() returns NULL (its frame-object allocation fails), so the f == NULL branch is taken; then
  2. PyUnicode_FromString("<sys>") itself returns NULL, leaving *filename == NULL.

The NULL *filename then reaches a Py_DECREF:

  • if setup_context() returns success (registry and __name__ already present in globals, so no further allocation is needed), do_warn() runs its cleanup Py_DECREF(filename) at L1139 — NULL deref; or
  • if setup_context() instead hits handle_error: (L1084), that path runs Py_DECREF(*filename) (L1087, not Py_XDECREF) — NULL deref.

Suggested fix

    *filename = PyUnicode_FromString("<sys>");
    if (*filename == NULL) {
        goto handle_error;
    }

and at handle_error: use Py_XDECREF(*filename) (since *filename may legitimately be NULL there).

Notes

Found by OOM-injection fuzzing (set_nomemory). Same pattern as gh-146080 (Py_DECREF(NULL) in an _ssl.c error label). Code is long-standing, so 3.13–3.15 are likely affected as well (unverified).

Found using fusil by @vstinner.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.16.0a0 (heads/main:bfecfcc2a86, Jun 18 2026, 13:48:35) [Clang 22.1.2 (1ubuntu1)]

Linked PRs
  • gh-151767
  • gh-154715

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

從 Python/_warnings.c 中的 setup_context() 和 do_warn() 開始,特別檢查 f == NULL 分支以及報告中描述的 handle_error 清理。使用 _testcapi.set_nomemory(0, 0) 執行隨附的 Python 重現程式;當配置失敗時警告發出不再發生 segfault(包括兩個清理路徑)即表示完成。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
c, python
領域
backend
Issue 類型
缺陷
難度
3/5
預估耗時
1-2 天
活躍度
停滯
描述清晰度
描述清楚
新手友好度
35/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。