Pourquoi et pour quoi
Pendant le développement, les choses ne sont pas toujours fluides. Il y a des problèmes qui n'apparaissent pas lors des tests, mais après la sortie. Pour de tels cas, nous avons créé un petit système pour détecter les exceptions et les erreurs internes.
Prise d'exception
Pour que le programme nous dise avant le crash (en dehors du débogueur) quel est le problème, vous pouvez utiliser la fonction de traitement du signal .
Quelques exemples de tels signaux:
signal(SIGABRT, abort_handler);
signal(SIGFPE, floating_point_handler);
signal(SIGILL, illegal_instruction_handler);
Gestionnaires de signaux
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;
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)
{
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);
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;
MINIDUMP_TYPE dump_flags = MINIDUMP_TYPE(MiniDumpNormal | MiniDumpFilterMemory | MiniDumpScanMemory);
char* logFileContent = nullptr;
DWORD logFileContentSize = 0;
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;
}
, , (, , ), , :

C# + WPF,
:
- Poursuivre l'exécution du programme (s'il s'agit d'une erreur interne)
- Signaler un problème (la pile vole vers le presse-papiers, l'utilisateur va sur le serveur Discord dans la rubrique souhaitée)
- Abandonner un programme