私ではなく、コンパイラです

2026/07/01 16:41

私ではなく、コンパイラです

RSS: https://news.ycombinator.com/rss

要約

日本語訳:

最近の Rust コンパイラにおける重大な誤コンパイルは、積極的な最適化が安全な高レベルコードを正しくないローレベル命令に変異させる方法を示した。土曜日の夕方に、JavaScript エンジンのパーサーの再構成中に

consume_test
関数において分岐を消去するために
self.0 += x as u32;
という処理を行いながら、著者はパースが失敗することを見つけ、アセンブリの検査により最適化後に
inc esi
命令が欠落しているか上書きされていることが判明した。この問題は Rust 1.94.0-nightly を
rustc --edition=2024 -Copt-level=3 -Clto
でコンパイルして再現可能であり、
-Cno-prepopulate-passes
を追加すると未初期化のメモリからの読み込みが露見した。一方、
-Zmir-opt-level=0
を使用すれば MIR 段階でバグは修正された。キャストを明示的なブロックに変える (
self.0 += if x { 1 } else { 0 };
) と問題が解決し、正しいパース (8 ノードで 14ns) が復元された。この事象は
p-critical
および
i-miscompile
というラベルが付与され、報告された課題 61,000 件以上の中でこれほど重大な誤コンパイルが出現したのはわずか 7 件の一つに過ぎない。Hanna Kruppe によって 18 時間以内にマージされた修正はコードの変更を必要とせずに安全性を回復させ、コンパイラパスが仮定を満たさない限り、安全な Rust の抽象化であっても不安定なアセンブリを生み出す可能性があることを強調している。この事象は、そのようなバグが安定版リリースで完全に解決されるまで、パフォーマンスにクリティカルな本番システムにおいて nightly バイルドや極限の最適化レベルを使用する際には注意を払うことの重要性を示している。

本文

開発者が狂っていないのはコンパイラだった:Rust コンパイルの奇妙な誤動作と解決記

開発者はかつて、「これは俺のせいじゃない。コンパイラのせいだ!」と呟いたことがあります。しかし、今回は実際にその通りだったという稀な体験談です。

1. バグを発見する瞬間

JavaScript エンジンのパーサーをリファクタリング中、従来のコードパターンを改善しようとしていました。

元のコード(一般的なパターン)

impl LexerConsumer {
    #[inline]
    pub fn consume(&mut self) {
        self.0 += 1;
    }

    #[inline]
    pub fn consume_test(&mut self, store: &LexStore, expected: TokenKind) -> bool {
        if self.peek(store) == expected {
            self.consume();
            true
        } else {
            false
        }
    }
}

改善しようとしたコード

生成されるアセンブリコードが美しく、かつバイト数も減少しましたが、動作に問題が発生しました。

#[inline]
pub fn consume_test(&mut self, store: &LexStore, expected: TokenKind) -> bool {
    let x = self.peek(store) == expected;
    self.0 += x as u32; // ここで問題が発生
    x
}

発生したエラー

Bash ヒストリ上に

for
ループの解析で以下のエラーが出ました。

> joe parse - 'for (var lol; false; false) {}'
Error was found
Diagnostic { kind: E079, flag: Flag(11529215046068469773), byte: 5, current_token: Var }
Parse error

解決への試み(偽の解決)

x as u32
の挙動を確認するため、明示的な分岐を書き換えてみました。

#[inline]
pub fn consume_test(&mut self, store: &LexStore, expected: TokenKind) -> bool {
    let x = self.peek(store) == expected;
    self.0 += if x { 1 } else { 0 }; // これなら正常に動作
    x
}

これで問題は解消されました。自信を持っていましたが、何か見落としていることに気づきました。


2. コンパイラが原因と判明

開発者は通常「bool を u32 として扱う仕組み」を理解しているはずですが、今回は**コンパイルの誤翻訳(Miscompilation)**が起きていることが分かりました。

自前のビルドシステムでアセンブリを確認

cargo asm
のラッパーではなく、自作のビルドシステム(TypeScript + Deno)を使用して、特定の関数のアセンブリコードを可視化しました。

コマンド例:

> x -b --fn ForOrInOfStatement 1 --dry  
MKDIR ./out
RUN rustc src/main.rs ... # (略)
RUN mold -melf_x86_64 -o ./out/joe ...
RUN bash -c nm out/joe | rustfilt | grep ForOrInOfStatement ...

アセンブリコードの分析

Rust コードでは以下の構造になっています。

fn ForOrInOfStatement(...) -> Termination {
    // ... 
    if lex.peek_test(store, TokenKind::LParen) { ... }
    
    if !lex.consume_test(store, TokenKind::LParen) {
        return raise_diagnostic(...); // エラーhere
    }
    // match 文で分岐が行われるはずだが...
}

問題のアセンブリコードの箇所

ForOrInOfStatement
関数のアセンブリを確認すると、重要な命令が欠落していました。

> x -b --fn ForOrInOfStatement 1
000000000021e290 <joe::fe::parser_handlers::ForOrInOfStatement>:
  21e290:              ff c6                    inc    esi       # lex.consume() // for
  21e292:              89 f0                    mov    eax,esi
  ...

重要な発見:

  • inc esi
    (インクリメント) が呼ばれていました。
  • しかし、その後の処理で
    TokenKind::LParen
    との比較が行われた際、インクリメントされなかった値が使用されていた迹象が見えた
  • 実際には
    consume_test
    内の
    self.0 += x as u32
    が正常に実行されたように見えたが、コンパイラがそれを誤って解釈していた。

疑問:

*   `# consume_test で self.0 += x as u32 と書かれなかったのか?`
*   `# WAIT.... WHO ATE MY INC ESI?! (誰が私の inc esi を喰らったのだ!)`

3. 調査と原因の特定

誤翻訳の可能性を裏付けるため、詳細な調査を行いました。

リバースエンジニアリングによる確認

  • LLVM IR の最適化前を確認するために
    -Cno-prepopulate-passes
    を使用。
    • 初期化されていないメモリからのロードを検出可能。
  • Rust/MIR の問題か LLVM の問題かを区別するため
    -Zmir-opt-level=0
    を使用。
    • これにより問題が解決し、原因は Rust コンパイラ側にあることが確認された。

ミニマルな再現例(MRE)の作成

単に「馬鹿なコードを書いたわけではない」ことを証明するために、最小化された再現例を作成しました。

Issue 登録

  • タイトル:
    Suspected miscompilation
    (疑わしい誤翻訳)
    • 「コンパイルが正しいと断言している場合、自分自身を責めるための防御壁」として「suspected」を付加。
  • 環境: Rust nightly 1.94.0-nightly
  • 状況: Nightly で修正されているかもしれないと考えたが、依然として問題が発生していた。

4. 対応と解決

翌日、目覚めた時点でコミュニティによる迅速な対応が行われていました。

コミュニティの対応

  1. Hanna Kruppe による修正 PR がオープンされていた。
  2. Issue ラベル:
    • p-critical
      (重大)
    • i-miscompile
      (誤翻訳)
  3. ステータス:
    • Rust の全問題のうち、これらのラベルを併せ持つのはわずか 7 つ(その 1 つ)。
    • p-critical
      ラベル自体も合計 247 件しか存在しない。

結論:コンパイラーの危険なバグ

この種の誤翻訳は「プログラマーと言語の間の契約」を破るため、最も危険なバグの一つとされています。安全に書かれたコードが必ずしも安全とは限らないことを示す典型例です。

  • 解決までの期間: 問題が発生してから18 時間以内で修正がマージ(Landed)。
  • 拍手を送りたい人:
    tmiasko
    および
    hanna-kruppe
    の迅速な対応に対して感謝する。

まとめ

この体験を通じて、以下のことを学びました。

  • 「これは俺のせいじゃない。コンパイラのせいだ!」 という言葉は、実際には正しい場合がある。
  • Rust コンパイラと戦い勝つことができた経験を得た。
  • コミュニティの迅速な対応により、重大なセキュリティや安定性のリスクを早期に解消することが可能になった。

これからの Rust 開発において、コンパイルの振る舞いを疑うことは決して馬鹿げたことではないことを確認しました。

同じ日のほかのニュース

一覧に戻る →

2026/07/05 8:41

鼻スプレーで脳の老化を逆転させることに成功した科学者たち

## Japanese Translation: テックス大学医学部ナーシュ K.ヴァシスト医学部の画期的な研究、アショーク・シェッティ医師をリーダーとし、再生医療研究所の下でマドフ・リラヴァーティ・ナラーヤナ氏とマハエダール・コダーリ氏といったシニア研究者が含まれたこの研究は、単純な 2 回投与の鼻スプレーが神経炎症性を逆転させ、脳機能を回復させることを示している。同研究は「細胞外小胞ジャーナル」(15(2): e70232, 2026)に発表され、数週間で炎症低減を示し、効果は数ヶ月持続することが確認された。治療法では、血脳関門を手術なしで回避しながらマイクロ RNA を直接脳組織へ届ける細胞外小胞(EVs)を使用している。細胞レベルにおいて、この治療は神経細胞のミトコンドリアを「充電」し、酸化ストレスを軽減すると同時に、NLRP3 インフラマソームおよび cGAS-STING シグナル経路といった炎症経路を抑制した。行動学試験では、対照群と比較して親しみのある物体を認識する能力や新たな環境を検出する能力に顕著な改善が確認された。シェッティ医師は、その成果が性別間で一貫性があり類似しており、このアプローチを「普遍的」と表現した。国立老人研究所(NIA)による支援を受けながら、特許出願が提出され、これは侵襲的な処置や月単位の薬物療法に代わる最小限の投与 regimes に向けた画期的な進歩を示している。2020 年の約 51 万4000 件から 2060 年には約 100 万件へと倍増するとの予測を踏まえれば、新たな認知症患者数の増加が待つのであり、このタイミングでの進展は意義深いが、世界規模で増大しつつある認知障害の負担を軽減しながら、従来の介入に伴うリスクを最小限に抑えるための変革的な一歩を提供している。

2026/07/05 4:41

Fable を用いた Command & Conquer: Generals の macOS、iPhone、iPad 向けネイティブ移植

## Japanese Translation: Zero Hour は、Apple Silicon Mac、iPhone および iPad 向けに公式ネイティブアプリケーションとして利用可能となり、DirectX 8 エンジンを Metal に変換する堅牢な翻訳パイプラインを採用しており、エミュレーションを必要とせずに動作します。このポータブルは fbraz3 が作成した GeneralsX プロジェクトを基盤とし、タップ選択、ドラッグボックス選択、ピンチによる拡大縮小など、基本的なタッチ操作を統合しています。macOS へのインストールには、外部的アセット(約 2.7 GB のバンドル)を抽出するために Steam コピーの所有が必要ですが、iOS バージョンはこれらのアセットがアプリケーションバンドル内に含められており、独立した体験を実現しています。開発プロセスには、Ammaar Reshi の指揮のもとで Claude Code が大幅な工数を投入し、MoltenVK や GPL v3 ライセンス付きコードなどのオープンソースツールを活用して、レガシーの PC アーキテクチャと最新の ARM64 ハードウェアを接続しました。Xcode 設定や特定のビルドスクリプトなどインストール前提条件が関わりますが、ユーザーはモバイルデバイス上で高性能の実時間戦略ゲームプレイを楽しむことができます。ただし、iOS ユーザーは長時間セッション中の潜在的なメモリ制限や、稀なバックグラウンド化時クラッシュについて留意する必要があります。

2026/07/05 6:51

GPT-5.5 Codex の推論トークンクラスタリングが性能低下を引き起こしている可能性があります

## Japanese Translation: 分析の結果、Codex ファミリーにおいて GPT-5.5 に特有の重大な異常が判明した。2026 年 2 月と 6 月 27 日の間、865 セッションから抽出された 390,195 トークン記録を検査したところ、GPT-5.5 の応答は過剰に正確な 516 トークンで終了する傾向があり、さらに 1034 トークンおよび 1552 トークンを周辺にクラスタリングしていた。GPT-5.5 は全応答の 19.3% に過ぎないにもかかわらず、正確な 516 トークンでのイベントの 82% を引き起こしており、非 GPT-5.5 モデルで観察されたレートと比較して約 33.6 倍高い。他のバージョン(GPT-5.4、GPT-5.2、および一部の GPT-5.3 バリエーション)では、これらの固定境界でのクラスタリングは著しく小さい。このパターンは分析深度の大幅な低下と相関しており、平均的な推論トークン強度は 2 月には 268.1 から 5 月には 107 トークン未満まで減少し、P90 も 772 から 344 トークンへと低下した。この異常は、GPT-5.5 の実行が正確な 516 トークンで終了する場合に複雑なコーディングタスクに対して誤った回答を返す過去の問題と関連している。固定トークン数でのクラスタリングは自然な変動ではなく閾値境界に似ており、推論予算のカップ、アクティブルーティングによる截断、スケジューラーの制限、または GPT-5.5 に特有のその他の内部閾値がある可能性を示唆している。この行動はEarlier モデルとの比較で severe な能力低下を示しており、高リスクなプログラミングシナリオにおける GPT-5.5 ファミリーの有用性を制限する可能性がある。専門家からは、これが劣化したサービス階級なのか、特定の内部ロジックなのか、またはその他の原因なのかを明らかにするために即時の調査を要請し、モデルと値ごとにトークンカウントイベントを照会して正確な値の数を比較したり、異なる GPT バージョンで複雑なタスクを再現するたり、正確な 516 トークンの応答とより長い推論出力を分離して行う品質評価を実施するなど、検証手順が提案されている。

私ではなく、コンパイラです | そっか~ニュース