Getting information about where c++ exceptions are

2019-01-22 04:50发布

I've got a c++ app that wraps large parts of code in try blocks. When I catch exceptions I can return the user to a stable state, which is nice. But I'm not longer receiving crash dumps. I'd really like to figure out where in the code the exception is taking place, so I can log it and fix it.

Being able to get a dump without halting the application would be ideal, but I'm not sure that's possible.

Is there some way I can figure out where the exception was thrown from within the catch block? If it's useful, I'm using native msvc++ on windows xp and higher. My plan is to simply log the crashes to a file on the various users' machines, and then upload the crashlogs once they get to a certain size.

5条回答
看我几分像从前
2楼-- · 2019-01-22 05:08

It's possible to design your exceptions to include source file names & line numbers. In order to do so, you need to create a class derived from std::exception to contain the information. In the example below, I have a library of exceptions for my application including my_exception. I also have a traced_error which is a template exception class derived from my application-level exceptions. The traced_error exception holds information about the filename & line number, and calls the application-level exception class' what() method to get detailed error information.

#include <cstdlib>
#include <string>
#include <stdexcept>
#include <iostream>
using namespace std;


template<class EX>
class traced_error : virtual public std::exception, virtual public EX
{
public:
    traced_error(const std::string& file, int line, const EX& ex)
    :   EX(ex),
        line_(line),
        file_(file)
    {       
    }

    const char* what() const
    {
        std::stringstream ss;
        static std::string msg;
        ss << "File: " << file_ << " Line: " << line_ << " Error: " << EX::what();
        msg = ss.str().c_str();
        return msg.c_str();
    }

    int line_;
    std::string file_;
};

template<class EX> traced_error<EX> make_traced_error(const std::string& file, int line, const EX& ex)
{
    return traced_error<EX>(file, line, ex);
}


class my_exception : virtual public std::exception
{
public:
    my_exception() {};

    const char* what() const
    {
        return "my_exception's what";
    }
};

#define throwx(EX) (throw make_traced_error(__FILE__,__LINE__,EX))


int main()
{
    try
    {
        throwx(my_exception());
    }
    catch( const std::exception& ex )
    {
        cout << ex.what();
    }
    return 0;
}

The output of this program is:

File: .\main.cpp Line: 57 Error: my_exception's what

You could also redesign this so that the application-level exceptions derive from traced_error instead of the other way round, in case you would rather catch specific application-level exceptions. In your catch, you can log the error to a log file & create a dump file using MiniDumpWriteDump().

查看更多
霸刀☆藐视天下
3楼-- · 2019-01-22 05:23

What you need is to analyze the stack to figure out where the exception came from. For msvc there is a lib called dbghelp.dll that can help you log out the exceptions. In general what I do is to log out a minidump file and use this to replay the issue beside using the right program database (pdb file). This works on a customer systems that do not come with source code or to whom you won't want to give pdbs.

查看更多
迷人小祖宗
4楼-- · 2019-01-22 05:24

You can write dumps using MiniDumpWriteDump function.

If you're using C++ exceptions, then you can simply include file/line/function information (so you'll see it as text if you call std::exception.what()) in any place where you throw that exception (using ____FUNCTION____, ____FILE____ and ____LINE____ macros).

If you're trying to catch OS exceptions, then crashing the application will be probably a better choice.

查看更多
霸刀☆藐视天下
5楼-- · 2019-01-22 05:25

One trick that is compiler independent is to wrap the throw statement in a function. The function can perform other duties before throwing the exception, such as recording to a log file. It also makes a handy place to put a breakpoint. If you create a macro to call the function you can automatically include the __FILE__ and __LINE__ where the throw occurred.

查看更多
对你真心纯属浪费
6楼-- · 2019-01-22 05:31

This is possible with using SEH (structured exception handling). The point is that MSVC implements C++ exceptions via SEH. On the other hand the pure SEH is much more powerful and flexible.

That's what you should do. Instead of using pure C++ try/catch blocks like this:

try
{
    DoSomething();
} catch(MyExc& exc)
{
    // process the exception
}

You should wrap the inner code block DoSomething with the SEH block:

void DoSomething()
{
    __try {
        DoSomethingInner();
    }
    __except (DumpExc(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) {
        // never get there
    }
}

void DumpEx(EXCEPTION_POINTERS* pExc)
{
    // Call MiniDumpWriteDump to produce the needed dump file
}

That is, inside the C++ try/catch block we place another raw SEH block, which only dumps all the exceptions without catching them.

See here for an example of using MiniDumpWriteDump.

查看更多
登录 后发表回答