Anzeigen von Ausnahmeinformationen vor dem Notausgang

Warum und wofür


Während der Entwicklung laufen die Dinge nicht immer reibungslos. Es gibt Probleme, die nicht bei den Tests, sondern nach der Veröffentlichung auftreten. In solchen Fällen haben wir ein kleines System zum Abfangen von Ausnahmen und internen Fehlern erstellt.


Ausnahme fangen


Damit das Programm uns vor dem Absturz (außerhalb des Debuggers) das Problem mitteilt, können Sie die Signalverarbeitungsfunktion verwenden .


Einige Beispiele für solche Signale:


    signal(SIGABRT, abort_handler); //  ,    nullptr   
    signal(SIGFPE, floating_point_handler); //      
    signal(SIGILL, illegal_instruction_handler); //     intrinsics (SSE/AVX/Other) 

Signalhandler



inline void abort_handler(int signal)
{
    handler_base("Application is aborting");
}

inline void floating_point_handler(int signal)
{
    handler_base("Floating point error");
}

inline void illegal_instruction_handler(int signal)
{
    if (!CPU::Info.hasFeature(CPUFeature::SSE42))
        handler_base("SSE4.2 and AVX instructions isn't legal on your CPU");
    else if (!CPU::Info.hasFeature(CPUFeature::AVX)) 
        handler_base("AVX instructions isn't legal on your CPU");
    else
        handler_base("Illegal instruction");
}

(_set_invalid_parameter_handler), (_set_new_handler) .


: callstack'a


, , . , CallStack. : StackWalker


: dump-


, Dump .


using MINIDUMPWRITEDUMP = BOOL(WINAPI*)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
    CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
    CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
    CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
    );

LONG WriteMinidump(struct _EXCEPTION_POINTERS* pExceptionInfo)
{
    long retval = EXCEPTION_CONTINUE_SEARCH;

    // firstly see if dbghelp.dll is around and has the function we need
    // look next to the EXE first, as the one in System32 might be old
    // (e.g. Windows 2000)
    HMODULE hDll = nullptr;
    string_path szDbgHelpPath;

    if (GetModuleFileName(nullptr, szDbgHelpPath, _MAX_PATH))
    {
        char* pSlash = strchr(szDbgHelpPath, '\\');
        if (pSlash)
        {
            const char dbgHelpStr[] = "DBGHELP.DLL";
            xr_strcpy(pSlash + 1, sizeof(dbgHelpStr), dbgHelpStr);
            hDll = LoadLibraryA(szDbgHelpPath);
        }
    }

    if (!hDll)
    {
        //  dbgHelp 
        hDll = LoadLibraryA("DBGHELP.DLL");
    }

    LPCSTR szResult = nullptr;

    if (hDll)
    {
        MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
        if (pDump)
        {
            string512 ErrorString = { NULL };
            DWORD ErrorSysCode = NULL;
            DWORD ErrorStringSize = NULL;

            string_path szDumpPath = { 0 };
            string_path szFilename = { 0 };
            string_path szScratch = { 0 };
            string64 t_stemp = { 0 };

            timestamp(t_stemp);
            xr_strcat(szDumpPath, DumpFilePath);

            //    : App Name, User Name, Time, Ext
            xr_strcat(szFilename, Core.ApplicationName);
            xr_strcat(szFilename, "_");
            xr_strcat(szFilename, Core.UserName);
            xr_strcat(szFilename, "_");
            xr_strcat(szFilename, t_stemp);
            xr_strcat(szFilename, ".mdmp");

            xr_strcat(szDumpPath, szFilename);

            //  
            HANDLE hFile = CreateFileA(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
            if (INVALID_HANDLE_VALUE == hFile)
            {
                //    ,    
                ZeroMemory(szDumpPath, sizeof(szDumpPath));
                xr_strcat(szDumpPath, szFilename);
                hFile = CreateFileA(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
            }
            if (hFile != INVALID_HANDLE_VALUE)
            {
                _MINIDUMP_EXCEPTION_INFORMATION ExInfo;

                ExInfo.ThreadId = GetCurrentThreadId();
                ExInfo.ExceptionPointers = pExceptionInfo;
                ExInfo.ClientPointers = NULL;

                //  Dump 
                MINIDUMP_TYPE dump_flags = MINIDUMP_TYPE(MiniDumpNormal | MiniDumpFilterMemory | MiniDumpScanMemory);

                //   
                char* logFileContent = nullptr;
                DWORD logFileContentSize = 0;

/////////////////////////////////////
                //        (logFileContent)
/////////////////////////////////////

        MINIDUMP_USER_STREAM_INFORMATION UserStreamsInfo = { 0 };
                MINIDUMP_USER_STREAM LogFileUserStream = { 0 };

                if (logFileContent)
                {
                    UserStreamsInfo.UserStreamCount = 1;
                    LogFileUserStream.Buffer = logFileContent; //   
                    LogFileUserStream.BufferSize = logFileContentSize; //  
                    LogFileUserStream.Type = MINIDUMP_STREAM_TYPE::CommentStreamA; // 
                    UserStreamsInfo.UserStreamArray = &LogFileUserStream;
                }

                BOOL bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, dump_flags, &ExInfo, &UserStreamsInfo, nullptr);
                if (bOK)
                {
                    xr_sprintf(szScratch, "Saved dump file to '%s'", szDumpPath);
                    szResult = szScratch;
                    retval = EXCEPTION_EXECUTE_HANDLER;
                }
                else
                {
                    ErrorSysCode = GetLastError();
                    ErrorStringSize = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, ErrorSysCode, 0, ErrorString, sizeof(ErrorString) - 1, nullptr);

                    if (!!ErrorString && ErrorSysCode && ErrorStringSize)
                        xr_sprintf(szScratch, "Failed to save dump file to '%s' (error %d '%s')", szDumpPath, ErrorSysCode, ErrorString);
                    else
                        xr_sprintf(szScratch, "Failed to save dump file to '%s' (No system error)", szDumpPath);
                    szResult = szScratch;

                }
                CloseHandle(hFile);
            }
            else
            {
                ErrorSysCode = GetLastError();
                ErrorStringSize = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, ErrorSysCode, 0, ErrorString, sizeof(ErrorString) - 1, nullptr);

                if (!!ErrorString && ErrorSysCode && ErrorStringSize)
                    xr_sprintf(szScratch, "Failed to create dump file '%s' (error %d '%s')", szDumpPath, ErrorSysCode, ErrorString);
                else
                    xr_sprintf(szScratch, "Failed to create dump file '%s' (No system error)", szDumpPath);
                szResult = szScratch;
            }
        }
        else
            szResult = "DBGHELP.DLL too old";
    }
    else
        szResult = "DBGHELP.DLL not found";

    return retval;
}


, , (, , ), , :
Bild
C# + WPF,


:


  • Setzen Sie die Programmausführung fort (wenn dies ein interner Fehler ist)
  • Ein Problem melden (der Stapel fliegt in die Zwischenablage, der Benutzer wechselt im gewünschten Thema zum Discord-Server).
  • Programm abbrechen

Source: https://habr.com/ru/post/undefined/


All Articles