世界を動かす技術を、日本語で。

RipGrepのmuslバイナリは、非常に大きな検索中に時折セグメンテーションフォルトを引き起こす

2026年8月1日原文(github.com)

概要

  • ripgrep 15.2.0 をOpenSUSE Tumbleweed Linux x86_64で利用時のバグ報告
  • 非常に大規模なファイルツリー を高並列で検索するとSIGSEGVクラッシュが発生
  • musl libcのmallocng/calloc 経由でopendir呼び出し時に発生
  • 再現手順 やクラッシュ時のバックトレース情報を詳細に記載
  • 期待動作 はセグフォルトしないこと

ripgrep 15.2.0のSIGSEGVクラッシュ報告

  • ripgrep 15.2.0 (rev e89fff8)を利用
    • pcre2, simd(SSE2, SSSE3, AVX2) サポート
    • PCRE2 10.45(JIT有効)
  • インストール方法
    • OpenAI Codexバンドル版、または公式リリースバイナリ(x86_64-unknown-linux-musl)
    • デバッグシンボル付きでcross build(CROSS_CONTAINER_ENGINE=podman CARGO_PROFILE_RELEASE_DEBUG=true ~/.cargo/bin/cross build --release --target x86_64-unknown-linux-musl)
  • OS環境
    • OpenSUSE Tumbleweed Linux x86_64
  • バグ内容
    • x86_64-unknown-linux-musl向けにビルドしたripgrepで、 大規模なディレクトリツリー を高並列で検索時、 SIGSEGV (セグメンテーションフォールト)発生
    • クラッシュ箇所は musl libcのmallocngのメタデータ整合性アサーション
    • opendirからcalloc経由で発生
  • 再現手順
    • generate_repro_tree.py を実行し、約20GiB/180万ファイルのツリーを生成
    • そのツリーのルートで、存在しない文字列を rgで無限ループ検索
      • 例: while true; do rg tnoheueunotshisnthukoethnsueothnsiuothonesuioseuinth; done
    • 24コア/十分なRAM環境で1分ほどでSIGSEGV発生
  • 実際の挙動
    • coredump発生
    • バックトレース例(抜粋):
      • get_meta → __malloc_allzerop → calloc → opendir → std::sys::fs::unix::readdir → ...
    • Rustの標準ライブラリ、ignore crateのwalk処理、スレッド生成、バックトレース取得などが呼び出しスタックに確認
  • 期待される挙動
    • セグメンテーションフォールトが発生しないこと
    • 正常に検索が完了すること

追加情報・参考

  • core dumpおよび該当rgバイナリ も取得済み
  • 根本原因 はmusl libcのmallocng内部のヒープメタデータ破損によるものと推測
  • 大規模並列ファイルアクセス 時のmallocngの脆弱性やripgrepのスレッドセーフティに問題の可能性

ripgrepやmusl libc利用者へのアドバイス

  • 大規模ディレクトリ での高並列検索時は注意
  • glibcターゲット でのビルドや並列度制限も暫定回避策
  • ripgrepやmusl libcのアップデート 状況を随時確認
  • バグレポート提出時は再現手順・環境・バックトレース を詳細に添付

Hackerたちの意見

カーネルバグの分析の方がリンクするにはいいかもね: https://github.com/dfoxfranke/ripgrep-3494-analysis.

魂のない読めないAIのゴミ

いい調査だけど、説明がめちゃくちゃだね。追加のTLBフラッシュはエラーじゃないよ。(CPUは気が向いたときにいつでもフラッシュしていいからね。)エラーの原因は、ゼロページのPTEが存在してはいけないときに存在していたことみたい。これって、(a)CPUの移行が不適切なタイミングで起こる複雑なレースか、(b)zapパスのバグが一時的に間違ったPTEを露出させているかのどちらかだと思う。あと、ゼロページにはpfnゼロがないと思う。もし予想を立てるなら、直接ページテーブルをzapすることで、CPUが解放されて再利用されたテーブルのキャッシュされたエントリを読み取ることができてしまっているんじゃないかな。うわぁ。こういうのは前にデバッグしたことがあるよ。

オーバーフローはまだオーバーフローするし、use-after-freeもまだ使った後に使うし、muslのマスクレースもまだレースする。面白いね。コンピュータ詩を除けば、結論は「Linux 7.0 + musl 1.2.5のどこかに問題がある」って感じだけど、再現は同じ物理的なThreadripper CPUでしか起きてなくて、しかも負荷がかかったときだけだから、ハードウェアの問題はまだ否定できてないね。

AI生成のバグレポートを読むのは最悪だね。

読もうとしたけど「Headline」で諦めた… バグ分析から引用すると: >「Headline」。クラッシュは本物で再現可能。muslの計測を使って、プロセス内のメカニズムを正確に特定する:スレッド自身が新しくフォールトした匿名ページに保存したデータが、そのスレッドのリロードから約10命令後には見えなくなる。なぜなら、ページのバックが関数の途中で置き換えられるから。フォールトが発生した瞬間のpagemapの読み取りでは、バックはカーネルのゼロページになっている。キャプチャしたコアダンプは、クラッシュ地点を一致する仮想アドレスで確認している。このメカニズムは、per-VMA-lockの匿名フォールトのファストパスと、同時に発生するmunmapのTLBシュートダウンとの相互作用に限定される。Linux 7.0.12のソースレベルレビューでは、その相互作用に特定のレースがあることが確認され、v6.19/v7.0/v7.1/mainlineのgit比較では、munmapのティアダウン側でのv7.0で導入された変更がそれを広げていることがわかる。「スレッド自身が新しくフォールトした匿名ページに保存したデータが、そのスレッドのリロードから約10命令後には見えなくなる。なぜなら、ページのバックが関数の途中で置き換えられるから。」 -> ??? ページの「バック」って何? 新しくフォールトした? フライドポテト? 「約10命令後」? 「フォールトが発生した瞬間のpagemapの読み取りでは、バックはカーネルのゼロページになっている。」 -> バック? 「このメカニズムは、per-VMA-lockの匿名フォールトのファストパスと、同時に発生するmunmapのTLBシュートダウンとの相互作用に限定される。」 -> メカニズムが「限定される」ってどういうこと? もっと色々あるけど、これは…言葉が繋がってるだけ。何もない。どうやって人はこれを読んで理解するんだろう。もし本物の技術的な文章がどうあるべきか忘れてる人がいたら、これがサンプルだよ(私は著者じゃないけど):https://yifan.lu/2019/01/11/the-first-f00d-exploit/

いや、そうじゃないよ。典型的なLLMの無駄話分析だね。正しい分析かもしれないけど(あまり読めなかったけど)、読むのがめんどくさい。人間が同じ分析をしてたら、1/5の長さで書いてたと思うよ。

なんでmuslcだけでバグが発生するの?他のlibcではどうなの?

偶然だね。それに、特定の一台のマシンでしか発生しない。

おそらく、muslのアロケータが新しくフォールトしたページをアプリに直接露出させるからだと思う。他のアロケータは、複数のページを一度に事前に割り当てる傾向があるから、レースウィンドウが狭くなるんだよね。

普通はmuslのスレッドスタックサイズを疑うけど、カーネルバグは確認されたの?

codexの検索がひどいのも納得だわ。

Hacker Newsで議論の続きを見る