Adem Aygun
Adem Aygun

Reputation: 582

exception handling stack trace in VC++

I am new in to C++ programming. _set_invalid_parameter_handler give me function name,file and line when I pass invalid parameter to a C++ system function -for ex.:in _tmain printf line generates error-, but I want to get function name, file and line of my programming, not about system function.

void myInvalidParameterHandler(const wchar_t* expression,
    const wchar_t* function,
    const wchar_t* file,
    unsigned int line,
    uintptr_t pReserved)
{
    wprintf(L"Invalid parameter detected in function %s."
        L" File: %s Line: %d\n", function, file, line);
    wprintf(L"Expression: %s\n", expression);
    call_stack st;
    st.stack.back();
    cout << st.stack.back().to_string();
    cout << st.to_string();

}

int _tmain(int argc, _TCHAR* argv[])
{
    char* formatString;
    _invalid_parameter_handler oldHandler, newHandler;
    newHandler = myInvalidParameterHandler;
    oldHandler = _set_invalid_parameter_handler(newHandler);
    formatString = NULL;
    printf(formatString); // I want to get this line
    return 0;
}

in this sample myInvalidParameterHandler generates below output: function = printf, file = f:\dd\vctools\crt\crtw32\stdio\printf.c, expression = (format != NULL) , line = 54

But I want to get something like: function = _tmain , file : ...\MySample.cpp , line = (printf line in mysample.cpp) How can I do that ?(like C# stack trace) ?

I also tried stack walker (call_stack), it gives me self line and i could not get my need by this way.

EDIT : Did not answer anyone yet . PLEASE HELP. 2015.02.25 16:42 Turkiye(Athens zone)

Upvotes: 1

Views: 641

Answers (1)

Elmue
Elmue

Reputation: 8148

The problem is that in C++ the callstack is not as easy available as in C#.

To get the callstack in an application which is released to the public you need the original source code, original DLL file, the original PDB file and a dump file.

You can generate a dump file in your code with MiniDumpWriteDump() in your crash handler. But this needs a structued exception.

So you must write:

#define SEH_ARG_EXCEPTION 0xE0415247 // "ARG"
void myInvalidParameterHandler(....) // all params are NULL in a release build
{
    RaiseException(SEH_ARG_EXCEPTION, EXCEPTION_NONCONTINUABLE, 0, NULL);
}

and in a structured exception handler you catch this:

__try
{
    Execute your code with invalid argument 
}
__except(ExceptionHandler(GetExceptionInformation())) 
{
}

static int ExceptionHandler(EXCEPTION_POINTERS* pk_Ptr)
{
    switch (pk_Ptr->ExceptionRecord->ExceptionCode)
    {
        case EXCEPTION_BREAKPOINT:
        case EXCEPTION_SINGLE_STEP:
            return EXCEPTION_CONTINUE_SEARCH;
    }

    MINIDUMP_EXCEPTION_INFORMATION k_Mini; 
    k_Mini.ThreadId          = GetCurrentThreadId(); 
    k_Mini.ExceptionPointers = pk_Ptr; 
    k_Mini.ClientPointers    = FALSE; 

    HANDLE h_File = CreateFile(L"DumpPath\\XYZ.dmp", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)

    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), h_File, MINIDUMP_TYPE, &k_Mini, 0, 0);

    CloseHandle(h_File);

    MessageBox(NULL, L"The application has crashed.\nA Minidump has been written to: XYZ.dmp\nPlease send this file to [email protected]", L"Fatal Error", MB_ICONSTOP | MB_TOPMOST);
    TerminateProcess(GetCurrentProcess(), 0);
    return EXCEPTION_EXECUTE_HANDLER;
}

You will then have a DMP file on disk which your user must send to you so you can load it into Visual Studio and get the crash location from the stacktrace.

Important: You need the exact original code and DLL and PDB file for this to work.

Upvotes: 1

Related Questions