■クラッシュするプログラムの原因追及
Visual C++ 限定です
VC6 VC7 で動作確認しました


作成したプログラムを実行するとなぜかクラッシュしてOSの落とされる
こういうバグって原因が凄く見つけにくいですよね

無限ループなら、開発環境のブレークで原因をある程度推測することができますけど
ポインタ関連のミスなどは、気がついたらプログラムがOSに落とされているため、
クラッシュの原因を追究するのには、プログラムを追いかけ追いかけ、
ものすごい時間がかかってしまいます

そこで、アプリケーションのクラッシュ時にOSから落とされる前に、
アプリケーションに特定の処理を実行させたいと思います


■まずはクラッシュするアプリケーション

#include <stdio.h>

int err_no;

//配列以上のメモリにアクセスする関数
void crash(){
	int buf[1];
	for(int i=0;1;i++){
		printf("%d\t",buf[i]);
		err_no++;
	}
}

int main(){
	crash();
	printf("\n err_no %d\n",err_no);
	return 0;
}


上記プログラムでは関数crash内で配列の添え字以上のメモリにアクセスするために
実行すると問答無用でOSに落とされます






■そこでヘルプを検索してみると
try-except ステートメント という項目を見つけることが出来ます
これは Microsoft の拡張機能であり、ハードウェア例外またはソフトウェア例外が発生した場合においても
構造化例外処理が行われるようなことが書かれています



▼先方作成したプログラムにtry-exceptを付けてみます

#include <stdio.h>

int err_no;

//配列以上のメモリにアクセスする関数
void crash(){
	int buf[1];
	for(int i=0;1;i++){
		printf("%d\t",buf[i]);
		err_no++;
	}
}

int main(){
	__try{

		crash();

	}__except(1){
		printf("\n err_no %d\n",err_no);
		getchar();
	}
	return 0;
}


▼上記プログラムを実行すると

c:\>■■■.exe
・・・・
 err_no 3115



OSに落とされることなくクラッシュしたプログラムの内部情報を表示できました




■ウィンドウズアプリケーション
コンソールアプリケーションと同様に構造化例外処理を行えばいいみたいです


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	__try{

		crash();

	}__except(1){
		char str[128];
		sprintf(str,"%d",err_no);
		MessageBox(NULL,str,"ERR",0);
	}
	return 0;
}






■しかしクラッシュといっても必ず捕まるわけでないですから注意が必要です
たとえば、先方のcrash関数を書き換えてメモリに0を書き込むように変更すると
スタックに格納されている関数の戻り先アドレスが0で上書きされてしまい
例外も何も発生せずにプログラムは終了します


//配列以上のメモリにアクセスする関数
void crash(){
	int buf[1];
	for(int i=0;1;i++){
		buf[i]=0;
		err_no++;
	}
}




■まとめ
アプリケーションのクラッシュ時に、デバックおよびログが取れるとすれば
その後の原因の追究が凄く楽になります
また、アプリケーション自身が自分自身のエラーを取得して、プログラムを再起動させるなど
信頼性の高いアプリケーションが作成できるかもしれません

ただ、例外処理のハンドラ内でクラッシュすると、どうにもなりませんけど笑






▲トップページ > Windows と C++