CI: UBSan runs GIL-only and never against the JIT; two configurations already shipped by distros are unsanitized
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 77.2k
- フォーク
- 35.9k
- PR マージ指標
- PR 指標を取得中
説明
Feature or enhancement
Proposal
The UBSan job in .github/workflows/build.yml runs against exactly one configuration: GIL-enabled, no JIT. Two configurations that CI already builds — and that distributions already ship — are never sanitized. Both are cheap to add, and I have measured what each would have caught.
1. UBSan × free-threading: true
The sanitizer matrix pairs TSan with free-threading: {false, true} but UBSan only with false:
free-threading:
- false
- true
sanitizer:
- TSan
include:
- check-name: Undefined behavior
sanitizer: UBSan
free-threading: false
So files that only compile under Py_GIL_DISABLED are never built under UBSan. That is not a hypothetical gap: Python/uniqueid.c:185 shifted a negative per-thread refcount delta left, which is UB, and it fired from interpreter startup and from every GC cycle. Over the full suite with all suppressions disabled:
| UB reports | test failures | failing files | |
|---|---|---|---|
| before | 1762 | 529 | 61 |
| after #154915 | 0 | 0 | 0 |
Once #154915 lands, this configuration is green, so adding it is a regression guard rather than a source of new work.
2. UBSan × --enable-experimental-jit
jit.yml builds the JIT in several configurations and tail-call.yml builds --with-tail-call-interp, but neither is ever combined with a sanitizer. The JIT's own C code — the stencil patcher in Python/jit.c, and the tier-2 optimiser in Python/optimizer*.c which only compiles under -D_Py_TIER2=1 — is therefore never sanitized in CI.
This one has already proven productive when done by hand: gh-139269 (an unaligned uint64_t store in Python/jit.c's patch_* functions, which segfaulted release builds) was found by building --enable-experimental-jit with -fsanitize=address,undefined, and gh-142476 was an ASan-found leak in allocate_executor.
I ran the full test suite against a machine-code JIT build under UBSan, with every entry in Tools/ubsan/suppressions.txt disabled: clean, zero reports, 51,459 tests across 493 files, 4m50s. Verified non-vacuous — _testinternalcapi.get_jit_backend() returns jit and a hot loop produces real machine-code ranges, so this was the copy-and-patch JIT rather than a silent fallback to the uop interpreter.
Since it is already green, this is also a pure regression guard.
Two smaller findings from the same sweep
local-boundsis enabled nowhere.--with-undefined-behavior-sanitizerinjects plain-fsanitize=undefined, andlocal-boundsis not in that group even though it detects genuine UB. I built with it on and ran the full suite: zero findings, including no false positives from the trailing variable-length array idiom, which was the obvious risk. It looks free to add.float-divide-by-zero(also not in the group) yields exactly one hit,Modules/expat/xmlparse.c:869, in vendored libexpat, which deliberately relies on IEEE-754+infand documents that in a comment. Not worth enabling without excluding expat.
On cost
The usual objection to widening the matrix is build time. For reference, a full PGO + ThinLTO + UBSan build — the heaviest combination I tried, including the instrumented build, the profile run, the rebuild and the ThinLTO link — took 9 min 43 s at --jobs=8. A plain UBSan build is far cheaper, and the JIT suite run above took under five minutes.
(That PGO/LTO configuration found nothing new, incidentally. It is worth noting only because --enable-optimizations and --with-lto appear in no workflow at all, while Arch, Debian and python-build-standalone all ship them. UBSan's checks are source-level, so PGO/LTO mostly changes which UB is reached; miscompilation from UB would show up as test failures rather than sanitizer reports, which is a different exercise.)
Linked PRs
- #154915 — fixes the free-threaded UB, prerequisite for adding that matrix entry
Has this already been discussed elsewhere?
This is a follow-up to gh-148286.
Links to previous discussion of this feature:
- gh-148286
- gh-139269
- gh-142476
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
.github/workflows/build.yml から始め、その UBSan マトリックスを free-threading、JIT、tail-call の workflow 構成と比較してください。#154915 の前提条件を確認してから、関連する CI 構成を更新し、UBSan が提案されたビルドと local-bounds の考慮事項をカバーするようにしてください。新しいジョブが sanitizer の報告なしに正常に実行され、既存の CI カバレッジが維持されれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- github-actions, python
- 領域
- build-system, ci-cd, testing-qa
- issue の種類
- 機能追加
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 活発さ
- 静か
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 62/100