
Windows ARM64の.NET Runtime CIで発生したJITストレス下のクラッシュ問題を読み解く
.NET Runtimeの継続的インテグレーション環境で、Windows ARM64向けのテスト実行中にMicrosoft.Extensions.DependencyInjection.Testsがクラッシュする既知のビルドエラーが確認された。今回の問題は、通常の実行条件ではなくJITストレス環境下で発生している点が重要であり、単なる単体テスト失敗というより、CoreCLRやJITコンパイラ、ARM64プラットフォーム固有の挙動が交差する領域で起きた障害として見る必要がある。エラーメッセージには「Consistency check failed: AV in clr」と記録されており、CLR内部でアクセス違反に関連する整合性チェックが失敗したことを示している。さらに、同様のクラッシュが複数のビルドで再現しているため、一過性のインフラ障害ではなく、再現性を持つランタイム側の不具合として扱われている。
- Windows ARM64で確認された.NET Runtimeの既知ビルドエラー
- 何が起きたのかを整理する
- 「Consistency check failed: AV in clr」が示す深刻度
- なぜJITストレス環境でだけ問題が見つかるのか
- Linux ARM64でも類似問題が追跡されていた意味
- CIにおける「Known Build Error」の役割
- 依存性注入テストがランタイムの不具合を露出しやすい理由
- Windows ARM64における例外処理とJITの難しさ
- 開発者や利用者への影響はどこまであるのか
- 重複Issueとして閉じられた理由
- CIログから読み取れる実務上の教訓
- 今回の問題が示す.NET Runtime開発の現在地
- まとめ
Windows ARM64で確認された.NET Runtimeの既知ビルドエラー
今回の事象は、.NET RuntimeリポジトリにおけるCIスキャンで検出された既知ビルドエラーとして報告されたものだ。対象となったのはMicrosoft.Extensions.DependencyInjection.Testsで、実行環境はWindows ARM64、構成はRelease、さらにJITストレスが有効化されたテストレッグである。
表面的には依存性注入ライブラリのテストが落ちているように見えるが、エラー内容を読む限り、問題の本質はアプリケーションレベルのテストロジックではなく、CLR内部で発生したアクセス違反に近い。Consistency check failed: AV in clrというメッセージは、CLRが内部状態の矛盾や例外処理中の異常を検知したことを示しており、通常のアサーション失敗や期待値不一致とは性質が異なる。
この種のエラーは、ライブラリの公開APIに直接の問題があるとは限らない。むしろ、JITコンパイラが生成したコード、例外処理、メモリアクセス、ガベージコレクション、安全ポイント、最適化の相互作用など、ランタイム基盤の深い部分に原因が潜んでいる可能性がある。
何が起きたのかを整理する
報告内容によると、失敗したビルドレッグはwindows-arm64 Release-Microsoft.Extensions.DependencyInjection.Testsであり、エラーはJITストレスが有効なパイプラインで発生している。クラッシュ時の終了コードは-1073740286で、CLR内部の例外ハンドラであるCLRVectoredExceptionHandlerPhase3付近のアサーション失敗が記録されている。
JITストレスとは、JITコンパイラの通常とは異なるコード生成パスや最適化条件を意図的に通すための検証手法である。通常実行では見えにくい不具合を早期に発見するために使われ、ランタイム開発では非常に重要なテスト条件だ。特にARM64のように命令セットや呼び出し規約、レジスタ利用、スタック配置がx64とは異なる環境では、JITストレスによってプラットフォーム依存のバグが露出することがある。
今回の報告では、同じパイプライン上の複数ビルドで再発していることも明記されている。これにより、単発のマシン不調、ネットワーク障害、テストタイムアウトではなく、特定条件下で再現するクラッシュとして扱われたと考えられる。
| 項目 | 内容 |
|---|---|
| 対象テスト | Microsoft.Extensions.DependencyInjection.Tests |
| 実行環境 | Windows ARM64 |
| 構成 | Release |
| 条件 | JIT stress |
| 主なエラー | Consistency check failed: AV in clr |
| 関連領域 | CoreCLR、JIT、CodeGen、ARM64 |
| 位置づけ | 既知ビルドエラー、重複Issueとしてクローズ |
この表からも分かる通り、問題は依存性注入フレームワーク単体の振る舞いではなく、ランタイム検証の中でもかなり低レイヤーに近い領域で起きている。
「Consistency check failed: AV in clr」が示す深刻度
AV in clrのAVは、一般的にはAccess Violationを指す文脈で読まれる。つまり、CLR内部で不正なメモリアクセスに関係する例外が検知され、それが整合性チェックに引っかかったということだ。マネージドコードの例外、たとえばInvalidOperationExceptionやNullReferenceExceptionとは異なり、CLR内部でのアクセス違反はランタイムの安全性に関わるため、CI上では重大なシグナルになる。
.NETのようなマネージドランタイムでは、開発者が直接メモリを操作しない場面でも、内部ではJITがネイティブコードを生成し、ランタイムがスタックやヒープ、型情報、例外処理テーブルを管理している。そのため、JITが誤ったコードを生成した場合や、特定の最適化条件で例外処理の状態が破綻した場合、マネージドレイヤーのテストが突然CLR内部クラッシュとして現れることがある。
今回のテスト対象である依存性注入は、.NETアプリケーションの土台として広く使われる機能だ。ただし、依存性注入のテスト自体が直接メモリ破壊を引き起こしていると断定するのは早い。むしろ、依存性注入のテストが多様なジェネリック、リフレクション、デリゲート、式木、サービス解決パターンを通ることで、JITやランタイムの複雑な経路を刺激し、潜在バグを表面化させた可能性がある。
なぜJITストレス環境でだけ問題が見つかるのか
JITストレス環境は、通常のプロダクション実行とは異なる条件を意図的に作り出す。たとえば、通常なら選ばれない最適化パス、別のコード生成戦略、特殊なインライン化条件、レジスタ割り当ての変化などが発生しやすくなる。これにより、普段は隠れている不具合が検出される。
重要なのは、JITストレスで発生したバグが必ずしも一般ユーザー環境で即座に再現するとは限らない点だ。しかし、だからといって軽視できるわけではない。JITストレスはランタイムの耐久試験のようなものであり、ここで見つかった不具合は、将来的な最適化変更や別の実行条件によって通常環境にも顔を出す可能性がある。
特にARM64では、近年Windows環境での利用が拡大している。クラウド、開発用デバイス、省電力PC、エッジ環境などでARM64の重要性は増しており、.NET RuntimeとしてもARM64対応の品質は重要なテーマになっている。そのため、Windows ARM64かつJITストレスという限定条件であっても、CIでブロッキング扱いされる価値は十分にある。
Linux ARM64でも類似問題が追跡されていた意味
今回の報告では、同じテストがLinux ARM64のJITストレス環境でもクラッシュしている別Issueへの言及がある。この点はかなり示唆的だ。もしWindows ARM64だけで発生しているなら、Windows固有の例外処理、OS API、スレッド管理、アンワインド情報、ネイティブ例外ハンドリングの問題が強く疑われる。
一方で、Linux ARM64でも同じテストがJITストレス下でクラッシュしているなら、より共通のARM64コード生成やCoreCLR内部処理に原因がある可能性が高まる。もちろん、OSごとにクラッシュの見え方が違うことはあるが、同じテスト、同じJITストレス、同じARM64という条件が重なるなら、JITのARM64バックエンドやランタイム共通層に注目が集まるのは自然だ。
今回のIssueが重複としてクローズされている点も、個別の新規不具合というより、既に認識されている同系統の問題として整理されたことを意味する。CIのノイズを減らし、原因調査を一本化するためには、同じクラッシュパターンを重複Issueとしてまとめる運用が有効だ。
CIにおける「Known Build Error」の役割
.NET Runtimeのような巨大なオープンソースプロジェクトでは、日々多数のプラットフォーム、構成、テスト群がCIで実行される。すべての失敗を人間が手作業で分類するのは現実的ではないため、既知の失敗パターンを機械的に検出し、Known Build Errorとして管理する仕組みが重要になる。
Known Build Errorの役割は、単に「既に知っているから無視する」というものではない。むしろ、同じ失敗がどのパイプラインで、どの頻度で、どの範囲に広がっているかを可視化するためのラベルでもある。今回のように複数ビルドで再現し、特定テストと特定プラットフォームに紐づいている場合、問題の切り分けが進みやすくなる。
また、blocking-clean-ciのようなラベルが付いていることから、単なる記録ではなく、CIの健全性に影響する問題として扱われていることも読み取れる。クリーンなCI状態を保つことは、ランタイム開発では非常に重要だ。既知の失敗が放置されると、新たな回帰が埋もれ、開発者が本当に見るべきシグナルを見逃しやすくなる。
依存性注入テストがランタイムの不具合を露出しやすい理由
Microsoft.Extensions.DependencyInjectionは、.NETアプリケーションにおけるサービス登録と解決の基盤である。単純なクラス生成だけでなく、スコープ管理、ライフタイム制御、ジェネリック型、ファクトリ、オープンジェネリック、例外ケース、循環依存の検出など、多くの実行パターンを含む。
このようなテストは、ランタイムにとって意外に良いストレス源になる。依存関係の解決では、型情報の参照、コンストラクタ選択、デリゲート呼び出し、キャッシュ、動的な呼び出し経路が複雑に絡む。JITから見れば、さまざまなメソッド形状や呼び出しパターンを含むため、コード生成の境界条件を踏みやすい。
したがって、依存性注入テストが落ちているからといって、必ずしもDIコンテナのロジックに不具合があるとは限らない。むしろ、十分に複雑で現実的なワークロードを持つテストだからこそ、JITやCLRの深い問題を検知できたと見ることもできる。
Windows ARM64における例外処理とJITの難しさ
ARM64はx64とは異なる命令セットを持ち、レジスタの使い方、スタックフレーム、呼び出し規約、分岐、メモリアクセスの特性も異なる。JITコンパイラはこれらを正しく理解し、マネージドコードをプラットフォーム固有のネイティブコードに変換しなければならない。
さらにWindows環境では、例外処理やスタックアンワインドの仕組みがOSの規約と密接に関わる。CLRはマネージド例外だけでなく、ネイティブ例外、アクセス違反、ベクター例外ハンドラなどとも連携する必要がある。今回のスタックにCLRVectoredExceptionHandlerPhase3が現れている点は、まさにこの領域で異常が検出されたことを示している。
JITストレスによって生成コードが変わると、例外発生時のレジスタ状態やスタック状態も変化する。その中で、通常は通らない組み合わせが発生し、CLR内部の整合性チェックに引っかかることがある。こうした問題は再現条件が限定されがちだが、修正には非常に慎重な解析が求められる。
開発者や利用者への影響はどこまであるのか
一般の.NET利用者にとって、今回の問題が直ちに本番アプリケーションへ影響するとは言い切れない。条件はWindows ARM64、Release、JITストレス、特定テストという限定されたものだからだ。通常のアプリケーション実行ではJITストレスを有効にしないため、同じクラッシュがそのまま再現する可能性は高くない。
ただし、ランタイム開発の観点では重要度が高い。JITストレス下のクラッシュは、内部の前提がどこかで崩れている可能性を示す。もし原因がARM64コード生成の誤りであれば、将来的な最適化や別のコードパターンで通常環境にも影響するリスクがある。ランタイムの品質を高めるには、こうした限定条件の失敗を早期に潰していくことが欠かせない。
また、Windows ARM64の.NET利用が増えるほど、プラットフォーム固有のCI失敗は無視しにくくなる。開発者がARM64デバイスでビルドやテストを行う機会も増えており、ランタイムの安定性はエコシステム全体の信頼性に直結する。
重複Issueとして閉じられた理由
今回のIssueは新規報告として作成されたものの、最終的には別Issueの重複としてクローズされている。これは問題が解決済みという意味ではなく、同じ根本原因または同じクラッシュパターンとして既存の追跡先に統合されたという意味で読むべきだ。
オープンソースの大規模開発では、同じCI失敗が複数のビルドやプラットフォームで別々に報告されることがある。これを放置すると、議論、ログ、再現条件、修正状況が分散し、調査効率が落ちる。そのため、重複Issueを閉じて親となるIssueに情報を集約するのは標準的な運用だ。
今回のケースでは、Windows ARM64の失敗がLinux ARM64側の類似クラッシュと同系列として扱われた点がポイントになる。プラットフォームは異なるものの、JITストレス下で同じテストがクラッシュしているため、調査の中心はARM64共通のJITまたはCoreCLRの挙動に置かれる可能性が高い。
CIログから読み取れる実務上の教訓
この事例から得られる教訓は、CIの失敗を単純にテスト名だけで判断してはいけないということだ。Microsoft.Extensions.DependencyInjection.Testsが失敗しているからといって、依存性注入ライブラリの変更が原因とは限らない。低レイヤーのクラッシュでは、テスト名は「症状が出た場所」であり、「原因がある場所」とは限らない。
特に、終了コード、エラーメッセージ、実行環境、ストレス条件、再現ビルド数、関連ラベルを合わせて見ることが重要だ。今回なら、AV in clr、JIT stress、windows-arm64、area-CodeGen-coreclr、arch-arm64といった情報が、ランタイム内部のコード生成問題を強く示している。
CI運用では、こうしたメタ情報の蓄積が調査速度を大きく左右する。失敗ログそのものが膨大でも、適切なラベルと既知エラー分類があれば、開発者は優先度と担当領域を判断しやすくなる。
今回の問題が示す.NET Runtime開発の現在地
.NET Runtimeは成熟した基盤だが、成熟しているからこそ、テスト対象は通常ケースだけでは足りない。複数OS、複数CPUアーキテクチャ、DebugとRelease、GCモード、JIT最適化、ストレス設定など、多層的な検証が必要になる。今回のようなWindows ARM64のJITストレス失敗は、その検証網が機能している証拠でもある。
一見するとクラッシュ報告はネガティブに見えるが、CIで検出され、既知エラーとして分類され、関連Issueに集約されている流れは健全だ。問題がユーザー環境で広く表面化する前に、開発パイプライン上で捕捉できているからである。
ARM64は今後も重要度を増す領域であり、JITやCoreCLRの品質改善は.NET全体の競争力に直結する。今回のクラッシュは限定条件下のものだが、ランタイムの内部整合性を守るうえでは見逃せないシグナルだ。依存性注入テストの失敗という入口から、JITコード生成、例外処理、ARM64対応、CI健全性までがつながって見える点に、この事例の本質がある。
まとめ
Windows ARM64の.NET Runtime CIで発生したMicrosoft.Extensions.DependencyInjection.Testsのクラッシュは、JITストレス下でCLR内部の整合性チェックが失敗した既知ビルドエラーである。エラーの中心はConsistency check failed: AV in clrであり、通常のテスト失敗ではなく、CoreCLRやJITの低レイヤーに関わる問題として扱われている。
同様の現象がARM64環境で追跡されていること、複数ビルドで再現していること、CodeGenやJIT stressに関連するラベルが付与されていることから、単発のCIノイズではなく、ランタイム品質に関わる重要な障害と見るべきだ。
一般利用者への直接影響は限定的と考えられる一方で、.NET Runtime開発においては重大な検出である。JITストレスは未来の不具合を先回りして発見するための仕組みであり、そこで見つかったクラッシュは、プラットフォーム対応の完成度を高めるための重要な手がかりになる。今回の事例は、Windows ARM64時代の.NETにおいて、CI、JIT、CoreCLR、テスト基盤がいかに密接に結びついているかを示す象徴的なケースだ。