障害原因を生の CDP パイプトランスポートまで絞り込む

概要

  • Node.js のテストハーネスにより、Playwright、Puppeteer、Selenium、サードパーティパッケージを使わずに Edge のネイティブクラッシュを再現した。
  • Edge、プロファイルの状態、入力ファイル、CDP コマンド、終了手順を固定し、トランスポートだけを変更した。
  • パイプ経由の生の CDP では、プロファイルを再利用した後、2 番目または 3 番目のブラウザプロセスでクラッシュした。
  • ポート経由の生の CDP では 8 / 8 回の実行が完了し、ファイルサイズと SHA-256 ハッシュも一致した。

Playwright を除外する理由

これまでのテストで、元のプロファイル、ヘッドレスモード、download.save_as() は必須の原因ではないことが確認されていた。しかし、Playwright の起動動作とコマンドの実行順序は、依然としてシステム内に残っていた。

Playwright を使わずに同じネイティブ終了を再現できれば、Python アプリケーションと Playwright の高レベルな Download API が必要条件ではないことを立証できる。

簡略化したテストハーネスで使用するのは、以下のみである。

  • Node.js の標準モジュール
  • Microsoft Edge
  • 専用のテストプロファイル
  • ローカル HTTP サーバー
  • 生の CDP JSON メッセージ

依存関係のないテストハーネス

再現テストでは、以下の手順を実行する。

  1. localhost で HTTP サーバーを起動する。
  2. 決定論的な 5 MiB のファイルと、5 つのダウンロードリンクを含む HTML ページを生成する。
  3. テスト専用のユーザーデータディレクトリに新しい Edge プロファイルを作成する。
  4. ページを開き、CDP を通じてダウンロード動作を設定する。
  5. 各リンクをアクティブ化し、ファイルを待つ。
  6. ファイルサイズと SHA-256 を検証する。
  7. Browser.close で Edge を閉じる。
  8. 同じプロファイルを使用して、次の Edge プロセスを起動する。

このテストは、外部ウェブサイト、個人用 Edge プロファイル、拡張機能、認証状態に依存しない。

トランスポートの比較

CDP コマンドは、2 つのトランスポート経路を介して Edge に到達できる。

トランスポート 起動オプション 接続
パイプ --remote-debugging-pipe 専用の親子プロセス間パイプ
ポート --remote-debugging-port ローカル HTTP および WebSocket エンドポイント

どちらの経路でも CDP メッセージが伝送される。このため、残りの条件を固定した場合、トランスポートは有用な独立変数となる。

パイプでの結果

パイプのテストでは、次の形式を使用した。

node repro.mjs --transport pipe --iterations 5 --download-behavior allow

最初の Edge プロセスとそのダウンロードは完了した。その後、Edge は 2 番目のプロセス中に終了し、試行によっては 3 番目のプロセス中に終了した。

run=1 transport=pipe result=ok
run=2 transport=pipe result=failed
exit_code=3221225477 (0xC0000005)

失敗した実行の一部では、完全に書き込まれた 5 MiB の .crdownload ファイルが、最終的なファイル名に変更されないまま残った。これはダウンロード完了付近での障害と整合するが、正確な内部処理を特定するものではない。

ポートでの結果

変更したのはトランスポート引数だけである。

node repro.mjs --transport port --iterations 8 --download-behavior allow

8 つのプロセスはすべて正常に完了した。

run=1 transport=port result=ok
run=2 transport=port result=ok
run=3 transport=port result=ok
run=4 transport=port result=ok
run=5 transport=port result=ok
run=6 transport=port result=ok
run=7 transport=port result=ok
run=8 transport=port result=ok

ダウンロードされたすべてのファイルで、想定された 5 MiB のサイズと SHA-256 ハッシュが確認された。

制御変数

比較では、以下の入力を固定した。

  • Edge 152.0.4191.53 の実行ファイル
  • ユーザーデータディレクトリ
  • 生成した 5 MiB の HTTP レスポンス
  • HTML とリンクのアクティブ化
  • Browser.setDownloadBehavior コマンド
  • ターゲットの作成およびアタッチの順序
  • Browser.close による終了手順

独立変数は以下である。

A: --remote-debugging-pipe
B: --remote-debugging-port=<temporary local port>

クロスチェック

構成 観測結果
Edge 152 + パイプ経由の生の CDP 2 番目または 3 番目のプロセスでネイティブクラッシュ
Edge 152 + ポート経由の生の CDP 8 / 8 回成功
ポート経由で起動した Edge に Playwright をアタッチ 2 / 2 回成功
Playwright 同梱の Chromium 151 + 永続パイプ 25 / 25 回成功
新しい Edge プロファイル、最初のブラウザプロセスのみ 5 / 5 回成功

Chromium 151 と Edge 152 は同一バージョンではないため、この比較だけでは Edge 152 のリグレッションだと断定できない。一方で、テストした Chromium ベースのブラウザ経路すべてで障害が発生するわけではないことは示している。

絞り込まれた障害境界

再現条件は、観測された以下の組み合わせまで絞り込まれた。

Microsoft Edge 152
same profile reused by another Edge process
download performed under CDP control
remote-debugging-pipe transport
native process crash

記録された実行では、ポートトランスポートへの変更、同梱の Chromium ビルドへの変更、またはテストを最初の Edge プロセスのみに制限した場合、クラッシュは再現しなかった。

ポートでの 8 回の成功は有用な対照結果ではあるが、すべての環境でポート経路が安全であることの証明ではない。厳密に述べるなら、ほかの関連条件を固定したテスト環境と実行回数において、ポート経由ではクラッシュが再現しなかったということである。

次のテスト

最後の手順では、ウィンドウ表示、ヘッドレス、生の CDP の各実行で得られた Crashpad ダンプを比較し、それらの経路が同一のネイティブ障害シグネチャに収束するかどうかを判定する。