[FancyZones] Crash on launch: fix exception handler (#14609)

* fix stacktrace logging

* init logger before exception handler

* wchar check
This commit is contained in:
Seraphima Zykova 2021-11-23 21:41:10 +03:00 committed by GitHub
parent 8743c2329e
commit bd0db76e31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 51 deletions

View File

@ -9,10 +9,7 @@
#include "winapi_error.h" #include "winapi_error.h"
#include "../logger/logger.h" #include "../logger/logger.h"
static IMAGEHLP_SYMBOL64* pSymbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(TCHAR));
static IMAGEHLP_LINE64 line;
static BOOLEAN processingException = FALSE; static BOOLEAN processingException = FALSE;
static CHAR modulePath[MAX_PATH];
static inline const char* exceptionDescription(const DWORD& code) static inline const char* exceptionDescription(const DWORD& code)
{ {
@ -64,15 +61,15 @@ static inline const char* exceptionDescription(const DWORD& code)
} }
/* Returns the index of the last backslash in the file path */ /* Returns the index of the last backslash in the file path */
inline int GetFilenameStart(CHAR* path) inline int GetFilenameStart(wchar_t* path)
{ {
int pos = 0; int pos = 0;
int found = 0; int found = 0;
if (path != NULL) if (path != NULL)
{ {
while (path[pos] != '\0' && pos < MAX_PATH) while (path[pos] != L'\0' && pos < MAX_PATH)
{ {
if (path[pos] == '\\') if (path[pos] == L'\\')
{ {
found = pos + 1; found = pos + 1;
} }
@ -83,22 +80,73 @@ inline int GetFilenameStart(CHAR* path)
return found; return found;
} }
inline void LogStackTrace() inline std::wstring GetModuleName(HANDLE process, const STACKFRAME64& stack)
{ {
BOOL result; static wchar_t modulePath[MAX_PATH]{};
HANDLE thread; const size_t size = sizeof(modulePath);
HANDLE process; memset(&modulePath[0], '\0', size);
CONTEXT context;
STACKFRAME64 stack; DWORD64 moduleBase = SymGetModuleBase64(process, stack.AddrPC.Offset);
ULONG frame; if (!moduleBase)
DWORD64 dw64Displacement; {
DWORD dwDisplacement; Logger::error(L"Failed to get a module. {}", get_last_error_or_default(GetLastError()));
return std::wstring();
}
if (!GetModuleFileNameW((HINSTANCE)moduleBase, modulePath, MAX_PATH))
{
Logger::error(L"Failed to get a module path. {}", get_last_error_or_default(GetLastError()));
return std::wstring();
}
const int start = GetFilenameStart(modulePath);
return std::wstring(modulePath, start);
}
inline std::wstring GetName(HANDLE process, const STACKFRAME64& stack)
{
static IMAGEHLP_SYMBOL64* pSymbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(TCHAR));
if (!pSymbol)
{
return std::wstring();
}
memset(&stack, 0, sizeof(STACKFRAME64));
memset(pSymbol, '\0', sizeof(*pSymbol) + MAX_PATH); memset(pSymbol, '\0', sizeof(*pSymbol) + MAX_PATH);
memset(&modulePath[0], '\0', sizeof(modulePath)); pSymbol->MaxNameLength = MAX_PATH;
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
DWORD64 dw64Displacement = 0;
if (!SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, pSymbol))
{
Logger::error(L"Failed to get a symbol. {}", get_last_error_or_default(GetLastError()));
return std::wstring();
}
std::string str = pSymbol->Name;
return std::wstring(str.begin(), str.end());
}
inline std::wstring GetLine(HANDLE process, const STACKFRAME64& stack)
{
static IMAGEHLP_LINE64 line{};
memset(&line, '\0', sizeof(IMAGEHLP_LINE64));
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
line.LineNumber = 0; line.LineNumber = 0;
DWORD dwDisplacement = 0;
if (!SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line))
{
return std::wstring();
}
std::string fileName(line.FileName);
return L"(" + std::wstring(fileName.begin(), fileName.end()) + L":" + std::to_wstring(line.LineNumber) + L")";
}
inline void LogStackTrace()
{
CONTEXT context;
try try
{ {
RtlCaptureContext(&context); RtlCaptureContext(&context);
@ -109,9 +157,11 @@ inline void LogStackTrace()
return; return;
} }
process = GetCurrentProcess(); STACKFRAME64 stack;
thread = GetCurrentThread(); memset(&stack, 0, sizeof(STACKFRAME64));
dw64Displacement = 0;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
stack.AddrPC.Offset = context.Rip; stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat; stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp; stack.AddrStack.Offset = context.Rsp;
@ -119,8 +169,9 @@ inline void LogStackTrace()
stack.AddrFrame.Offset = context.Rbp; stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat; stack.AddrFrame.Mode = AddrModeFlat;
std::stringstream ss; BOOL result = false;
for (frame = 0;; frame++) std::wstringstream ss;
for (;;)
{ {
result = StackWalk64( result = StackWalk64(
IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_AMD64,
@ -138,34 +189,10 @@ inline void LogStackTrace()
break; break;
} }
pSymbol->MaxNameLength = MAX_PATH; ss << GetModuleName(process, stack) << "!" << GetName(process, stack) << GetLine(process, stack) << std::endl;
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
if (!SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, pSymbol))
{
Logger::error(L"Failed to get a symbol. {}", get_last_error_or_default(GetLastError()));
} }
line.LineNumber = 0; Logger::error(L"STACK TRACE\r\n{}", ss.str());
SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line);
DWORD64 moduleBase = SymGetModuleBase64(process, stack.AddrPC.Offset);
if (moduleBase)
{
if (!GetModuleFileNameA((HINSTANCE)moduleBase, modulePath, MAX_PATH))
{
Logger::error(L"Failed to get a module path. {}", get_last_error_or_default(GetLastError()));
}
}
else
{
Logger::error(L"Failed to get a module. {}", get_last_error_or_default(GetLastError()));
}
ss << std::string(modulePath).substr(GetFilenameStart(modulePath)) << "!" << pSymbol->Name << "(" << line.FileName << ":" << line.LineNumber << std::endl;
}
Logger::error("STACK TRACE\r\n{}", ss.str());
Logger::flush(); Logger::flush();
} }
@ -218,7 +245,6 @@ inline void InitSymbols()
{ {
// Preload symbols so they will be available in case of out-of-memory exception // Preload symbols so they will be available in case of out-of-memory exception
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
HANDLE process = GetCurrentProcess(); HANDLE process = GetCurrentProcess();
if (!SymInitialize(process, NULL, TRUE)) if (!SymInitialize(process, NULL, TRUE))
{ {

View File

@ -25,9 +25,8 @@ const std::wstring instanceMutexName = L"Local\\PowerToys_FancyZones_InstanceMut
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ int nCmdShow) int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR lpCmdLine, _In_ int nCmdShow)
{ {
winrt::init_apartment(); winrt::init_apartment();
InitUnhandledExceptionHandler_x64();
LoggerHelpers::init_logger(moduleName, internalPath, LogSettings::fancyZonesLoggerName); LoggerHelpers::init_logger(moduleName, internalPath, LogSettings::fancyZonesLoggerName);
InitUnhandledExceptionHandler_x64();
auto mutex = CreateMutex(nullptr, true, instanceMutexName.c_str()); auto mutex = CreateMutex(nullptr, true, instanceMutexName.c_str());
if (mutex == nullptr) if (mutex == nullptr)