Releaseビルドのアプリがクラッシュしたときに原因ソース行を特定する方法
若干タイトル詐欺です。
事前に設定しておけば、あとからソース行を特定できます。
想定環境
- OS: Windows11
- Compiler: MSVC
- ビルド設定ツール: CMake
- デスクトップアプリ開発
- 管理者権限を取得可能
要約
- レジストリ設定でdmpファイル(プロセスダンプ)出力をON
- ビルド設定でpdbファイル(デバッグシンボル)出力をON
- Visual Studioにdmpファイルを読み込ませる
- Releaseビルドでもクラッシュ箇所がソース行レベルで特定できる
プロセスダンプの出力設定
参考:
Windows検索窓にreg
と入力するとレジストリエディターが表示されるので起動する。
Ctrl+F
で検索ボックスを開き、Windows Error Reporting
について検索する。
検索対象はキーのみ、また完全一致のみを条件とする。
\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting
という項目にマッチするはず。
別の項目にマッチした場合はF3
を押すことで次の検索結果に移動できる。
Windows Error Reporting
を右クリック→新規→キーからLocalDumps
を作成する。
Dumpファイルの出力先を設定
LocalDumps
を右クリック→新規→展開可能な文字列を作成する。
作成した値の名前をDumpFolder
、値のデータをC:\Dumps
(任意)に設定する。
Dumpファイルに出力する内容を設定
LocalDumps
を右クリック→新規→DWORDを作成する。
作成した値の名前をDumpType
、値のデータを2
に設定する。
2
はフルダンプを意味しており、出来得る限りすべての情報をDumpファイルに出力する。
Dumpファイル数の最大数を設定
LocalDumps
を右クリック→新規→DWORDを作成する。
作成した値の名前をDumpCount
、値のデータを10
(1以上)に設定する。
Dumpファイルは1つが数GBになることも多いので、ストレージ容量に応じて値を変更することを推奨。
最終確認
下図のような値になっているか確認する。
ビルド設定でPDBファイル出力をONにする
参考:
PDB
ファイルはデバッグシンボルと呼ばれ、バイナリとソースコードのファイル名や行番号やシンボル情報 (変数名等) の対応関係を保持している。
デバッグ実行時、PDB
ファイルを参照してプログラムのステップ実行を可能にしている。
Relaseビルドでは通常PDB
ファイルは出力されないが、CMakeスクリプトに以下の設定を記述することで出力可能。
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi" CACHE STRING "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF" CACHE STRING "" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF" CACHE STRING "" FORCE)
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF" CACHE STRING "" FORCE)
サンプルプログラムを用意
Qtで作成。
ボタンを押したらNullアクセスでクラッシュする。
#include <QApplication>
#include <QPushButton>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
auto button = new QPushButton("Push");
QObject::connect(button, &QPushButton::clicked, []() {
QWidget* widget{nullptr};
widget->size();
});
button->show();
return a.exec();
}
ビルドする。
出力フォルダにPDBファイルが生成されていることを確認する。
プログラムを実行し、ボタンを押してクラッシュさせる。
レジストリエディターで設定したC:\Dumps
フォルダにDumpファイルが生成されている。
Visual StudioでDumpファイル解析
Visual Studioを起動し、「コードなしで続行」をクリックする。
ファイル→開く→ファイル を選択し、Dumpファイルを開く。
Dumpファイルの概要が表示される。
具体的にソースコードのどの行でクラッシュしたかを表示するため、シンボルパスの設定をクリックする。
今回はQtのバイナリが配置されているフォルダと、先程ビルドしたプログラムとPDBファイルがあるフォルダを追加する。
ネイティブのみでデバッグをクリックする。
プログラムがクラッシュした箇所がソースコードの行レベルで表示される。
感想
Releaseビルドで実行中に突然クラッシュしてもクラッシュ箇所を特定できるので便利。
Discussion