クラッシュで停止したとき、黄色い矢印の行だけを見ても原因に届かないことがあります。
この記事では、Call Stack を使って呼び出し元へ遡り、不正な値が入った場所を確認する手順をまとめます。
Call Stack (呼び出し履歴) の役割
プログラムが関数を呼び出すたびに、CPUは「どの関数から呼ばれたのか(終わったらどこに戻るのか)」という情報を、「スタック」というメモリ領域に順番に積み上げて(Pushして)いきます。
この積み上がった履歴を一覧表示してくれるのが Call Stack ウィンドウです。
開き方と見方
- デバッグ中に停止(ブレークポンイト、またはクラッシュ)した状態で、Visual Studioのメニューから 「デバッグ(Debug)」 -> 「ウィンドウ(Windows)」 -> 「呼び出し履歴(Call Stack)」 を開きます。(ショートカット: Ctrl + Alt + C)
- ウィンドウには、関数名がズラリと並びます。
一番上の行が「現在停止している関数」であり、下に行くほど「過去(呼び出し元)」に遡ります。

Call Stack の使い方(原因箇所の探し方)
例えば、関数が三段にネストしていて、一番奥でアクセス違反が起きたとします。
void CrashFunctionC()
{
int* p = NULL;
*p = 999;
}
void CrashFunctionB()
{
CrashFunctionC();
}
void CrashFunctionA()
{
CrashFunctionB();
}
停止した直後に見えるのは、一番上の CrashFunctionC() です。ここだけ見ても「NULLポインタを書いた」という事実しか分かりません。
原因を追うため、Call Stack ウィンドウで一段下(呼び出し元)の行をダブルクリックします。
すると、ソースコードのエディタが CrashFunctionB() や CrashFunctionA() に順に戻ります。さらに重要なのは、選んだフレームの時点に合わせてローカル変数の表示も切り替わることです。
この順番で戻ると、「どこからこのクラッシュ経路に入ったか」を落ち着いて追えます。黄色い矢印の行だけを見て終わらせないための道具が Call Stack です。
これが、Call Stack を使って呼び出し元へ遡る基本的な確認手順です。
MFC/Windows API の呼び出しを見分ける
MFCやWindowsデスクトップアプリをデバッグしていると、Call Stackの途中に、グレーの文字で大量の見慣れない関数が並んでいることがあります。
> MyProject.exe!CMyView::OnLButtonDown() 行 123
mfc140d.dll!CWnd::OnWndMsg()
mfc140d.dll!CWnd::WindowProc()
mfc140d.dll!AfxCallWndProc()
user32.dll!DispatchMessageW()
MyProject.exe!CWinThread::PumpMessage()
...
これは、Windows(user32.dll)がメッセージを送り、MFC フレームワーク(mfc140.dll)を経由して、最終的に OnLButtonDown が呼ばれた経路を示しています。
これらMFC本体やOS内部の処理バグであることは極めて稀ですので、基本的には 「自分が書いたソースコード(黒字で表示されていて、右端に行番号が出ている行)」 だけを飛び石のようにダブルクリックして遡り、「自分自身のコードが、どのUI操作から始まったのか」を確認するのに使います。
まとめ
- [ ] クラッシュした行だけでは足りない。呼び出し元から不正なデータの流れを確認する。
- [ ] Call Stack ウィンドウ(Ctrl+Alt+C)を開き、一つ下(呼び出し元)をダブルクリックして過去へ遡る。
- [ ] 遡った先で変数の状態を確認し、不正な引数がどこで入ったかを特定する。
- [ ] MFCやWindowsのシステム関数(グレーの行)は読み飛ばし、自分が書いたコード(黒字の行)だけを追う。
