VC++ 各种未处理异常的处理,并输出DUMP崩溃转储调试文件

本文包含:

信号处理器、STL标准库异常处理、STL未处理器异常处理、SEH结构化未处理异常处理、C++ 未定义虚函数异常处理、C/C++ 内存分配异常处理等。

设置异常处理器:

            // Windows platforms need to mount unhandled exception handlers so that they can print dump debug files for app crashes.
#if defined(_DEBUG)
            ::_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
#endif
            ::_set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT);

            ::_set_purecall_handler(Crt_HandlePureVirtualCall);
            ::_set_new_handler(Crt_NewHandler); /* std::set_new_handler(...) */

#if _MSC_VER >= 1400 
            ::_set_invalid_parameter_handler(Crt_InvalidParameterHandler);
#endif

            ::signal(SIGABRT, Crt_SigabrtHandler);
            ::signal(SIGINT, Crt_SigabrtHandler);
            ::signal(SIGTERM, Crt_SigabrtHandler);
            ::signal(SIGILL, Crt_SigabrtHandler);

            ::set_terminate(Crt_TerminateHandler);
            ::set_unexpected(Crt_UnexpectedHandler);

            ::SetUnhandledExceptionFilter(Seh_UnhandledExceptionFilter);

异常处理器实现:

        static ppp::string Seh_NewDumpFileName() noexcept
        {
            ppp::string path = ppp::GetExecutionFileName();
            std::size_t index = path.rfind(".");
            if (index != ppp::string::npos)
            {
                path = path.substr(0, index);
            }

            struct tm tm_;
            time_t datetime = time(NULL);
            localtime_s(&tm_, &datetime);

            char sz[1000];
            sprintf_s(sz, sizeof(sz), "%04d%02d%02d-%02d%02d%02d", 1900 + tm_.tm_year, 1 + tm_.tm_mon, tm_.tm_mday, tm_.tm_hour, tm_.tm_min, tm_.tm_sec);

            path = path + "-" + sz + ".dmp";
            path = "./" + path;
            path = ppp::io::File::RewritePath(path.data());
            path = ppp::io::File::GetFullPath(path.data());

            return path;
        }

        static LONG WINAPI Seh_UnhandledExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) noexcept
        {
            // Give user code a chance to approve or prevent writing a minidump.  If the
            // filter returns false, don't handle the exception at all.  If this method
            // was called as a result of an exception, returning false will cause
            // HandleException to call any previous handler or return
            // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear
            // as though this handler were not present at all.
            HANDLE hFile = CreateFileA(Seh_NewDumpFileName().data(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
            if (hFile != INVALID_HANDLE_VALUE)
            {
                MINIDUMP_EXCEPTION_INFORMATION exceptionParam;
                exceptionParam.ThreadId = GetCurrentThreadId();
                exceptionParam.ExceptionPointers = exceptionInfo;
                exceptionParam.ClientPointers = TRUE;

                MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithFullMemory, &exceptionParam, NULL, NULL);
                CloseHandle(hFile);
            }

            // The handler either took care of the invalid parameter problem itself,
            // or passed it on to another handler.  "Swallow" it by exiting, paralleling
            // the behavior of "swallowing" exceptions.
            exit(-1); /* abort(); */
            return EXCEPTION_EXECUTE_HANDLER;
        }
        
#if _MSC_VER >= 1400 
        // https://chromium.googlesource.com/breakpad/breakpad/src/+/master/client/windows/handler/exception_handler.cc
        static void __CRTDECL Crt_InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) noexcept
        {
            std::wcerr << L"Invalid parameter detected:" << std::endl;
            std::wcerr << L"Expression: " << expression << std::endl;
            std::wcerr << L"Function: " << function << std::endl;
            std::wcerr << L"File: " << file << std::endl;
            std::wcerr << L"Line: " << line << std::endl;

            _CrtDumpMemoryLeaks();
            _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
            _CrtMemDumpAllObjectsSince(NULL);
            _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);

            // Make up an exception record for the current thread and CPU context
            // to make it possible for the crash processor to classify these
            // as do regular crashes, and to make it humane for developers to
            // analyze them.
            EXCEPTION_RECORD exception_record = {};
            CONTEXT exception_context = {};
            EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };

            ::RtlCaptureContext(&exception_context);

            exception_record.ExceptionCode = STATUS_INVALID_PARAMETER;

            // We store pointers to the the expression and function strings,
            // and the line as exception parameters to make them easy to
            // access by the developer on the far side.
            exception_record.NumberParameters = 4;
            exception_record.ExceptionInformation[0] = reinterpret_cast<ULONG_PTR>(expression);
            exception_record.ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(file);
            exception_record.ExceptionInformation[2] = line;
            exception_record.ExceptionInformation[3] = reinterpret_cast<ULONG_PTR>(function);

            // Deliver exceptions to unhandled exception handler.
            Seh_UnhandledExceptionFilter(&exception_ptrs);
        }
#endif

        static int Seh_NoncontinuableException() noexcept
        {
            // Make up an exception record for the current thread and CPU context
            // to make it possible for the crash processor to classify these
            // as do regular crashes, and to make it humane for developers to
            // analyze them.
            EXCEPTION_RECORD exception_record = {};
            CONTEXT exception_context = {};
            EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };

            ::RtlCaptureContext(&exception_context);

            exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;

            // We store pointers to the the expression and function strings,
            // and the line as exception parameters to make them easy to
            // access by the developer on the far side.
            exception_record.NumberParameters = 3;
            exception_record.ExceptionInformation[0] = NULL;
            exception_record.ExceptionInformation[1] = NULL;
            exception_record.ExceptionInformation[2] = 0;

            // Deliver exceptions to unhandled exception handler.
            return Seh_UnhandledExceptionFilter(&exception_ptrs);
        }

        static int __CRTDECL Crt_NewHandler(size_t) noexcept
        {
            return Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_HandlePureVirtualCall() noexcept
        {
            Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_TerminateHandler() noexcept
        {
            Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_UnexpectedHandler() noexcept
        {
            Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_SigabrtHandler(int) noexcept
        {
            Seh_NoncontinuableException();
        }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值