クラッシュレポートの出力(Windows)¶
概要¶
Choreonoidには、アプリケーションが異常終了(クラッシュ)したときに、その原因を特定するための情報をファイルに書き出す機能があります。この機能は現在のところWindowsでのみ利用できます。
この機能を有効にしておくと、クラッシュした際に以下の2つのファイルが出力されます。
クラッシュレポート(.txt)
テキストファイルです。クラッシュした位置の呼出履歴(コールスタック)、例外の種類、読み込まれていたモジュールの一覧が記録されます。このファイル単体で、プログラムのどこで落ちたかが分かります。
ダンプファイル(.dmp)
クラッシュ時のプロセスの状態を記録したバイナリファイルです。Visual Studioなどのデバッガで開いて、より詳しく調べるために使います。
この機能は、以下のような状況で利用することを想定しています。
開発環境のない利用者のPCでのみ再現するクラッシュについて、利用者にレポートを送ってもらって原因を調べる
Choreonoidをベースとするアプリケーションを納品した先で発生したクラッシュの情報を受け取る
クラッシュが発生すると、以下のような通知ダイアログが表示され、レポートファイルの保存先が示されます。
Windowsでは、この機能がない場合、クラッシュ時にウィンドウが何も表示されないまま静かに終了することがあり、利用者には何が起きたのか分からないことがあります。この機能を有効にしておけば、クラッシュしたことがダイアログで伝わり、開発者に送るべきファイルも明確になります。
Windowsには同種の機能として、Windows Error Reporting(WER)のローカルダンプ機能がありますが、そちらは管理者権限でのレジストリの編集が必要で、得られるのもダンプファイルのみです。本機能は管理者権限を必要とせず、テキストのレポートが直接得られる点が異なります。
Choreonoidの利用者の方は、クラッシュに遭遇した場合、 機能の有効化 から 出力されるファイル までの内容を参考にして、出力されたファイルを開発者に送ってください。レポートの内容を自分で確認したい場合は レポートの読み方 を参照してください。 関数名と行番号を出力するには 以降は、主にChoreonoid本体やChoreonoidをベースとするアプリケーションの開発者を対象とした内容です。
機能の有効化¶
この機能はデフォルトでは無効になっています。レポートにはファイルのパスや読み込まれているモジュールの一覧が、ダンプファイルにはプロセスのメモリの内容が含まれるため、利用者が意図しないところでこうしたファイルが残ることのないようにしています。無効の場合は、関連するライブラリの読み込みも出力先ディレクトリの作成も行われません。
機能の有効化は、Choreonoidを起動する際の環境変数で行います。
環境変数 |
値 |
動作 |
|---|---|---|
CNOID_CRASH_DUMP |
未設定または空 |
無効(デフォルト) |
CNOID_CRASH_DUMP |
0 |
無効 |
CNOID_CRASH_DUMP |
full |
有効にし、ダンプファイルにプロセスのメモリ全体を含める |
CNOID_CRASH_DUMP |
上記以外の値(1 など) |
有効にする |
CNOID_CRASH_DUMP_DIR |
任意のパス |
出力先ディレクトリを変更する |
Choreonoidをベースとするアプリケーション(Choreonoidの App クラスを使用して構築されたもの)でも、同じ環境変数で有効になります。アプリケーション側でのコードの追加は不要です。
利用者に有効化してもらう場合は、以下のように環境変数を設定してから起動するバッチファイルを渡すのが確実です。
@echo off
set CNOID_CRASH_DUMP=1
start "" "C:\Program Files\Choreonoid\bin\choreonoid.exe"
"C:\Program Files\Choreonoid\bin\choreonoid.exe" の部分は、実際のインストール先に合わせて置き換えてください。
出力されるファイル¶
出力先¶
ファイルは以下のディレクトリに出力されます。
%LOCALAPPDATA%\<組織名>\<アプリケーション名>\CrashDumps
<組織名> と <アプリケーション名> はアプリケーションによって決まる名前で、Choreonoid本体ではどちらも "Choreonoid" です。したがってChoreonoid本体の場合、出力先は以下になります。
C:\Users\<ユーザ名>\AppData\Local\Choreonoid\Choreonoid\CrashDumps
出力先のディレクトリは自動的に作成されます。 CNOID_CRASH_DUMP_DIR を設定している場合は、そのディレクトリに出力されます。
AppData は隠しフォルダなので、エクスプローラで開くには、アドレスバーに
%LOCALAPPDATA%\Choreonoid\Choreonoid\CrashDumps
と入力するのが手軽です。
古いファイルは自動的に削除され、最大で10回分のクラッシュのファイルが保持されます。
注釈
出力先は、Choreonoidの設定ファイルが置かれる %APPDATA%(AppData\Roaming)ではなく、AppData\Local の側になります。ダンプファイルは大きく、またそのPCで起きた事象の記録であるため、移動ユーザプロファイルによって他のPCに同期される場所には置かないようにしています。これはWERのローカルダンプ機能のデフォルトの出力先(%LOCALAPPDATA%\CrashDumps)と同じ階層です。
ファイル名¶
ファイル名は以下の形式になります。
<実行ファイル名>_<日付>_<時刻>_<プロセスID>.txt
<実行ファイル名>_<日付>_<時刻>_<プロセスID>.dmp
例えば以下のようになります。
choreonoid_20260826_021646_2428.txt
choreonoid_20260826_021646_2428.dmp
同じクラッシュのレポートとダンプファイルは同じ名前になります。
ファイルのサイズ¶
ファイルのサイズは、Choreonoidの起動処理中にクラッシュさせた場合の実測で以下のようになります。
ファイル |
サイズ |
|---|---|
クラッシュレポート(.txt) |
約10KB |
ダンプファイル(デフォルト) |
約240KB |
ダンプファイル(CNOID_CRASH_DUMP=full の場合) |
約450MB |
レポートとデフォルトのダンプファイルは合わせて250KB程度なので、メールに添付して送ることができます。 full を指定した場合のダンプファイルは、ファイル転送サービスなどを使って送る必要があります。
レポートの読み方¶
クラッシュレポートは以下のような内容のテキストファイルです(モジュール一覧は途中を省略しています)。レポートの内容は、Choreonoidの表示言語によらず英語で出力されます。
Crash report of an application based on Choreonoid
Application : Choreonoid
Choreonoid ver. : 2.6.0
Executable : C:\Program Files\Choreonoid\bin\choreonoid.exe
Date : 2026-08-26 02:16:46
Process ID : 2428
Thread ID : 22692
Reason : Unhandled exception
Exception code : 0xC0000005 (EXCEPTION_ACCESS_VIOLATION)
Exception addr : 0x00007FFEE8DA6A4D
Faulting module : C:\Program Files\Choreonoid\bin\CnoidBase.dll
Fault offset : 0x0000000000076A4D
Access type : write to 0x0000000000000000
Dump file : C:\Users\<user>\AppData\Local\Choreonoid\Choreonoid\CrashDumps\choreonoid_20260826_021646_2428.dmp
Dump type : minidump
Call stack of the crashed thread (the most recent call first):
00 CnoidBase.dll + 0x00076A4D cnoid::MainWindow::Impl::Impl + 0x9D [MainWindow.cpp:149]
01 CnoidBase.dll + 0x00076F9A cnoid::MainWindow::MainWindow + 0xAA [MainWindow.cpp:138]
02 CnoidBase.dll + 0x000776AE cnoid::MainWindow::initialize + 0x3E [MainWindow.cpp:119]
03 CnoidBase.dll + 0x00035287 cnoid::App::Impl::initialize + 0xB77 [App.cpp:713]
04 CnoidBase.dll + 0x0002ECA2 cnoid::App::Impl::exec + 0x42 [App.cpp:881]
05 choreonoid.exe + 0x0000149E main + 0x20E [choreonoid.cpp:7]
06 choreonoid.exe + 0x000022FD qtEntryPoint + 0x15D [qtentrypoint_win.cpp:50]
07 choreonoid.exe + 0x0000171E __scrt_common_main_seh + 0x106 [exe_common.inl:288]
08 KERNEL32.DLL + 0x0001259D BaseThreadInitThunk + 0x1D (*)
09 ntdll.dll + 0x0005AF78 RtlUserThreadStart + 0x28 (*)
The debug information (PDB file) of the modules of the frames without a
source line is not available on this computer. A name marked with (*) is
just the exported symbol nearest to the address and is often a function
other than the one that actually contains it. The module name and the
offset in it are always exact, and the developer can identify the exact
position from them with the same binary and its debug information.
Loaded modules (100):
base address size time stamp file
0x00007FF7AA300000 0x00011000 0x6A8DCA30 C:\Program Files\Choreonoid\bin\choreonoid.exe
0x00007FFF9F5D0000 0x00218000 0xAC55DAA3 C:\WINDOWS\SYSTEM32\ntdll.dll
0x00007FFF9DE80000 0x000C4000 0xE4CACA22 C:\WINDOWS\System32\KERNEL32.DLL
...
Please send this file to the developer of the application. The dump file
listed above is also useful to investigate the details of the problem.
この例は、動作確認のために意図的にクラッシュを起こして得たものです。レポートは、クラッシュの概要、呼出履歴、モジュール一覧の3つの部分から構成されます。以下では各部分の読み方を説明します。
クラッシュの概要¶
レポートの冒頭には、クラッシュの概要が以下の項目で記録されます。
項目 |
意味 |
|---|---|
Application |
アプリケーション名 |
Choreonoid ver. |
ベースとなっているChoreonoidのバージョン |
Executable |
実行ファイルのパス |
Date |
クラッシュした日時 |
Process ID / Thread ID |
プロセスID / クラッシュしたスレッドのID |
Reason |
異常終了の種別(下記参照) |
Exception code |
例外コードとその名前(下記参照) |
Exception addr |
例外が発生したアドレス |
Faulting module |
例外が発生したモジュール(DLL/EXE)のパス |
Fault offset |
そのモジュール内でのオフセット |
Access type |
アクセス違反の場合、読み書きの別と対象アドレス |
Dump file |
対になるダンプファイルのパス |
Dump type |
minidump または full dump |
Faulting module と Fault offset は、Windowsのイベントビューアで「アプリケーションエラー」(イベントID 1000)として記録される「障害が発生しているモジュール名」「フォールト オフセット」と同じ意味の値です。イベントビューアを開かなくても、レポートから同じ情報が得られます。
Reason には以下のいずれかの値が出力されます。
値 |
意味 |
|---|---|
Unhandled exception |
処理されない例外が発生した(最も一般的なケース) |
Abnormal termination by the abort function |
abort関数が呼ばれた(assertの失敗など) |
An exception that is not caught by any handler |
どこでもcatchされないC++例外が発生した |
Call of a pure virtual function |
純粋仮想関数が呼ばれた |
An invalid parameter given to a runtime library function |
ランタイムライブラリが不正な引数を検出した |
Exception code としてよく出力されるのは以下のものです。
コード |
名前 |
意味 |
|---|---|---|
0xC0000005 |
EXCEPTION_ACCESS_VIOLATION |
アクセス違反。無効なポインタの読み書き。最も多いケース |
0xC0000094 |
EXCEPTION_INT_DIVIDE_BY_ZERO |
整数のゼロ除算 |
0xC00000FD |
EXCEPTION_STACK_OVERFLOW |
スタックオーバーフロー。無限再帰など |
0xC0000374 |
STATUS_HEAP_CORRUPTION |
ヒープの破壊が検出された |
0xE06D7363 |
C++ exception |
処理されないC++例外 |
呼出履歴¶
"Call stack of the crashed thread" 以下には、クラッシュしたスレッドの呼出履歴が記録されます。各行の形式は以下のとおりです。
番号 モジュール名 + モジュール内オフセット 関数名 + 関数内オフセット [ソースファイル:行番号]
上にある行ほど新しい呼び出しで、番号 00 の行がクラッシュした位置そのものです。
モジュール名とモジュール内オフセットは常に正確に出力されます。
関数名と行番号は、そのPCにモジュールのデバッグ情報(PDBファイル)がある場合にのみ出力されます。
関数名に (*) が付いているものは、PDBファイルがなかったために、そのアドレスの手前にある最も近いエクスポート関数の名前を表示したものです。実際にそのアドレスを含む関数とは限りません。上の例では、Windowsのシステムライブラリ(KERNEL32.DLL、ntdll.dll)がこれにあたります。
記録されるのはクラッシュしたスレッドのみです。他のスレッドの状態が必要な場合は、ダンプファイルを解析してください。
デバッグ情報がない場合でも、呼出履歴の並びとモジュール名・オフセットは正確なので、レポートから「どのモジュールのどの位置で落ちたか」は必ず分かります。開発者側で同じビルドのバイナリとデバッグ情報を用意しておけば、この情報から正確な位置を特定できます。デバッグ情報の準備については 関数名と行番号を出力するには を参照してください。
モジュール一覧¶
"Loaded modules" 以下には、クラッシュ時に読み込まれていたモジュールが、ベースアドレス、サイズ、タイムスタンプ、ファイルパスとともに列挙されます。これは以下のような用途に使えます。
プロセスに注入された第三者のDLLの有無を確認する。セキュリティソフト、画面オーバーレイ、フック型の常駐ソフトなどがクラッシュの原因になっていることがあり、その確認に使えます。
各モジュールがどのビルドのものであるかを、タイムスタンプとサイズから特定する。
関数名と行番号を出力するには¶
ここからは主に開発者向けの内容です。
上で述べたように、呼出履歴の並びとモジュール名・オフセットはデバッグ情報がなくても正確に出力されます。デバッグ情報が必要なのは、関数名と行番号を出力するためだけです。
Windowsでは、デバッグ情報は実行ファイル(EXE/DLL)とは別の「PDBファイル」に格納されます。関数名と行番号を出力するには、デバッグ情報付きでビルドを行い、PDBファイルを適切に配置する必要があります。
デバッグ情報付きのビルド¶
Visual C++のReleaseビルドでは、デフォルトではPDBファイルが生成されません。これを生成するには、Choreonoidのビルド時にCMakeの ENABLE_MSVC_DEBUG_INFO_FOR_RELEASE オプションをONにします。
cmake -B build -G "Visual Studio 17 2022" -DENABLE_MSVC_DEBUG_INFO_FOR_RELEASE=ON
CMakeのGUIツールで設定する場合は、通常の設定一覧に表示されるこのオプションのチェックをONにしてください。CMakeでの設定操作については オプション機能のビルド を参照してください。
このオプションはコンパイラに /Zi を、リンカに /DEBUG /OPT:REF /OPT:ICF を追加します。最適化のオプションは変わらないため、生成される機械語は同一であり、実行性能には影響しません。増えるのはビルド時間とPDBファイルのディスク容量(Choreonoid本体で1GB強)だけです。
注釈
PDB(Program Database)は、リンカが実行ファイルとは別に生成するデバッグ情報のファイルです。関数名や変数名とアドレスの対応、型情報、アドレスとソースファイル・行番号の対応表が格納されています。ソースコード自体は含まれません。Linuxではデバッグ情報がデフォルトで実行ファイルの中に含まれるのに対して、Windowsでは常に別ファイルとなるため、デバッグ情報を有効にしてもEXE/DLLのサイズはほとんど変わらず、PDBファイルを配布しなければデバッグ情報のないビルドと同等になります。
PDBファイルの配置¶
生成されたPDBファイルは、 cmake --install を実行すると、対応するEXE/DLLと同じディレクトリ(bin、lib\choreonoid-<バージョン>、およびその下の bodyhandler、customizer)にインストールされます。ビルドディレクトリでは bin\Release と lib\choreonoid-<バージョン>\Release 以下にあります。
なお、QtやVisual C++のランタイムなど、サードパーティのDLLにはPDBファイルはありません。
PDBファイルは、対応するEXE/DLLと同じディレクトリにあれば、レポートの出力時に自動的に見つけられます。したがって、以下の2通りの運用が可能です。
PDBファイルを配布物に同梱する
レポートに関数名と行番号が直接出力されるので、レポートを送ってもらうだけで済みます。配布物のサイズは増えます(Choreonoid本体で数百MB規模)。
PDBファイルを開発側で保管する
レポートにはモジュール名、オフセット、タイムスタンプが正確に出力されるので、同じビルドのPDBファイルと突き合わせれば位置を特定できます。この場合、リリースごとにPDBファイルを確実に保管しておく必要があります。
PDBファイルとバイナリの対応¶
PDBファイルには、リンク時に生成される固有のIDが記録されており、対応するバイナリにも同じIDが埋め込まれています。IDが一致しないPDBファイルは読み込まれません。したがって、以下の点に注意してください。
ビルドし直したバイナリに、以前のビルドのPDBファイルを使うことはできません。
「まずレポートだけを受け取り、後からPDB付きでビルドし直す」という段取りは成立しません。関数名と行番号まで得るには、最初からデバッグ情報付きでビルドしたバイナリでクラッシュを再現してもらう必要があります。
この仕組みによって、誤ったPDBファイルによる間違った解析結果が出ることが防がれています。
ダンプファイルの解析¶
レポートの情報だけでは足りない場合、例えば他のスレッドの状態や、変数・オブジェクトの中身を確認したい場合は、ダンプファイルをデバッガで開いて解析します。ここではVisual Studio 2022を使う場合の手順を示します。
Visual Studioを起動します。
.dmp ファイルをVisual Studioのウィンドウにドラッグ&ドロップします。メニューの「ファイル」-「開く」-「ファイル」から開いても構いません。
「ミニダンプ ファイルの概要」の画面が表示されるので、例外コードとモジュール一覧を確認します。
画面右の「アクション」から「ネイティブのみでデバッグ」をクリックします。
メニューの「デバッグ」-「ウィンドウ」-「呼び出し履歴」(Ctrl+Alt+C)で、呼出履歴を確認します。PDBファイルがあれば、関数名と行番号まで表示されます。
メニューの「デバッグ」-「ウィンドウ」-「モジュール」(Ctrl+Alt+U)で、読み込まれていたモジュールを確認できます。
シンボルが解決されず関数名が表示されない場合は、「ツール」-「オプション」-「デバッグ」-「シンボル」で、PDBファイルのあるフォルダをシンボルファイルの場所として追加してください。Windowsのシステムライブラリの関数名も表示したい場合は、同じ設定で「Microsoft シンボル サーバー」を有効にします。
別のPCで生成されたダンプファイルを解析する場合は、以下の点に注意してください。
デフォルトのダンプファイル(ミニダンプ)にはモジュールのコード本体が含まれません。そのため、解析にはPDBファイルだけでなく、対になるEXE/DLLも必要です。x64でスタックの巻き戻しに使われる情報はバイナリ側に格納されているため、バイナリがないと呼出履歴自体が正しく得られません。
Visual Studioはシンボルファイルの場所をPDBファイルだけでなくバイナリの探索にも使用するので、EXE/DLLとPDBファイルを含むフォルダをシンボルファイルの場所に追加すれば解析できます。ダンプが生成されたPCのディレクトリ構成を再現する必要はありません。
制約と注意事項¶
この機能はWindows専用です。他のプラットフォームでは、環境変数を設定しても何も起きません。
呼出履歴に記録されるのは、クラッシュしたスレッドのみです。
クラッシュしたプロセス自身がレポートの出力を行うため、ヒープが激しく破壊されている場合には、関数名の解決に失敗することがあります。その場合もモジュール名とオフセットは出力されます。ヒープの破壊が検出されている場合(STATUS_HEAP_CORRUPTION)は、はじめから関数名の解決を行いません。
スタックオーバーフローに備えてメインスレッドのスタックには余裕を確保していますが、ワーカースレッドでスタックオーバーフローが発生した場合は、レポートを出力できないことがあります。
レポートにはファイルパスとモジュール一覧が、ダンプファイルにはプロセスのメモリの内容が含まれます。第三者に送る際は内容を確認してください。
この機能はWindows Error Reporting(WER)の動作を妨げません。イベントログのアプリケーションエラー(ID 1000)は従来どおり記録され、WERのローカルダンプ機能を設定している環境ではそちらのダンプも生成されます。
--headless、--batch、--non-interactiveの各オプションで起動した場合は、自動実行がモーダルダイアログで停止しないように、通知ダイアログは表示されません。その場合は同じ内容が標準エラー出力に出力されます。クラッシュに備える処理は起動時のごく早い段階で組み込まれます。その時点ではまだメッセージの翻訳データが読み込まれていないため、起動直後にクラッシュした場合のダイアログは英語で表示されます。
性能への影響¶
この機能を有効にしても、通常の実行中に行われる処理はありません。クラッシュしたときにOSから呼び出される仕組みであり、常駐するスレッドや定期的な処理はなく、関数呼び出しや例外処理が遅くなることもありません。
有効にした場合のコストは起動時の初期化のみで、起動時間の差は測定誤差の範囲内、メモリ使用量の増加は約0.2MB(デバッグ用のライブラリ dbghelp.dll が読み込まれるため)です。またスタックオーバーフローの検出用の余裕として、メインスレッドで使用可能なスタックが64KB分狭くなります。
Linuxの場合¶
Linuxでは、OSの標準的な仕組みであるCoreファイル(Coreダンプ)を使って、同様の情報を得ることができます。詳細は Coreファイルを用いて落ちた箇所を探る方法 を参照してください。Linuxではデバッグ情報が実行ファイルの中に含まれるため、PDBファイルのような別ファイルを用意する必要はありません。