デバッグ関連の処理

通常、デバッグする際、ブレークポイントや。ファイル出力などを行い、動きを確認したりします。
しかし、再現方法がわからなかったり、発生頻度が稀なバグをデバッグするとき、当たりが付けずらく、困ってしまうこともあります。
.mapと.codを利用したデバッグもあわせてご覧下さい。

メモリリークしているポインタがわからない場合

VC++のアウトプットウィンドウには、デバッグビルドの場合、メモリリークの情報が表示されます。
ファイル名がきちんと出てくればよいのですが、ライブラリのソースファイルや、ファイル名無しの情報が出てくることがあります。
その場合、
Detected memory leaks!
Dumping objects ->
{152} normal block at 0x00386450, 30 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.
上記のようなメッセージがアウトプットウィンドウに表示されます。
{152}というのがありますが、これは、152番目にnewされたポインタということをあらわします。
この152を使って、どこで割り当てられているかを知ることが出来ます。
_CrtSetBreakAlloc という関数が有り、この関数は、指定されたメモリ生成の順番に、ブレークポイントを設定する関数です。
この関数をプログラムの開始時に呼び出せば、リークしているメモリを生成しているところでブレークすることが出来ます。

ただし、順番が常に変わったり、外部プログラム(DLLや呼び出しているexe)では効果はありません。

致命的エラーを受け取る

頻度が稀なバグはなかなか調査が大変です。
ただし、アプリケーションエラーのようなエラーは、ログを取っておけばある程度、情報を取得することが出来ます。
__try〜__except機構を利用します。

__try〜__except機構は、冷害が発生した場合、__exceptで指定した関数を呼び出すことが出来ます。
また、GetExceptionInformation APIを呼び出すことも出来ます。
GetExceptionInformation APIはStack OverFllowなどの情報を取得できます。
ここの関数に処理を入れていくことは、不可能ではないですが、規模が大きい場合には漏れがあったり、手間がかかって島します。
なので、全体の処理の大本に仕掛けるのが良いでしょう。
Windows SDKでの処理であればメッセージループ、MFCを使っていれば、CWinAppのRun関数、ProcessShellCommand関数を実装し、その中で行います。
(ダイアログ、スレッドは試していません)

int CExceptTestApp::Run() {
    // TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください
    int nRet = -1;
    __try{  
        nRet = CWinApp::Run();
    }__except(Except(GetExceptionInformation())){
        //例外をそのまま返却して、アプリケーションを終了させる
    }

    return nRet;
}

BOOL CExceptTestApp::ProcessShellCommand( CCommandLineInfo& rCmdInfo ){
    __try{
        CWinApp::ProcessShellCommand(rCmdInfo);
    }__except(Except(GetExceptionInformation())){
        return FALSE;
    }
}


int CExceptTestApp::Except(LPEXCEPTION_POINTERS pExp){
    if(pExp){
        CString strExpCode = "UNKNOW";
        switch(pExp->ExceptionRecord->ExceptionCode){
        case EXCEPTION_ACCESS_VIOLATION:
            strExpCode = "EXCEPTION_ACCESS_VIOLATION";
            break;
        case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
            strExpCode = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
            break;
        case EXCEPTION_BREAKPOINT:
            strExpCode = "EXCEPTION_BREAKPOINT";
            break;
        case EXCEPTION_DATATYPE_MISALIGNMENT:
            strExpCode = "EXCEPTION_DATATYPE_MISALIGNMENT";
            break;
        case EXCEPTION_FLT_DENORMAL_OPERAND:
            strExpCode = "EXCEPTION_FLT_DENORMAL_OPERAND";
            break;
        case EXCEPTION_FLT_DIVIDE_BY_ZERO:
            strExpCode = "EXCEPTION_FLT_DIVIDE_BY_ZERO";
            break;
        case EXCEPTION_FLT_INEXACT_RESULT:
            strExpCode = "EXCEPTION_FLT_INEXACT_RESULT";
            break;
        case EXCEPTION_FLT_INVALID_OPERATION:
            strExpCode = "EXCEPTION_FLT_INVALID_OPERATION";
            break;
        case EXCEPTION_FLT_OVERFLOW:
            strExpCode = "EXCEPTION_FLT_OVERFLOW";
            break;
        case EXCEPTION_FLT_STACK_CHECK:
            strExpCode = "EXCEPTION_FLT_STACK_CHECK";
            break;
        case EXCEPTION_FLT_UNDERFLOW:
            strExpCode = "EXCEPTION_FLT_UNDERFLOW";
            break;
        case EXCEPTION_ILLEGAL_INSTRUCTION:
            strExpCode = "EXCEPTION_ILLEGAL_INSTRUCTION";
            break;
        case EXCEPTION_IN_PAGE_ERROR:
            strExpCode = "EXCEPTION_IN_PAGE_ERROR";
            break;
        case EXCEPTION_INT_DIVIDE_BY_ZERO:
            strExpCode = "EXCEPTION_INT_DIVIDE_BY_ZERO";
            break;
        case EXCEPTION_INT_OVERFLOW:
            strExpCode = "EXCEPTION_INT_OVERFLOW";
            break;
        case EXCEPTION_INVALID_DISPOSITION:
            strExpCode = "EXCEPTION_INVALID_DISPOSITION";
            break;
        case EXCEPTION_NONCONTINUABLE_EXCEPTION:
            strExpCode = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
            break;
        case EXCEPTION_PRIV_INSTRUCTION:
            strExpCode = "EXCEPTION_PRIV_INSTRUCTION";
            break;
        case EXCEPTION_SINGLE_STEP :
            strExpCode = "EXCEPTION_SINGLE_STEP";
            break;
        case EXCEPTION_STACK_OVERFLOW:
            strExpCode = "EXCEPTION_STACK_OVERFLOW";
            break;
        default:
            break;
        }
        CString strExpInfo;
        strExpInfo.Format("%d[0x%08X] : %s\r\n"
                          "           Flag = 0x%08X\r\n"
                          "           Address = 0x%08X\r\n"
                        ,pExp->ExceptionRecord->ExceptionCode
                        ,pExp->ExceptionRecord->ExceptionCode
                        ,strExpCode
                        ,pExp->ExceptionRecord->ExceptionFlags
                        ,pExp->ExceptionRecord->ExceptionAddress);
        AfxMessageBox(strExpInfo);
    }
    return 0;
}

この処理の AfxMessageBoxのところをファイル出力に変更すればログを取ることが出来ます。