From 7038cfdeb327d9f4ff74b350740a1184befa1312 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Wed, 10 Jun 2020 20:28:45 -0700 Subject: [PATCH] handle C++ exceptions, unpacking the internal structures to get the variable type (and any superclasses) being thrown --- interface/src/CrashHandler_Crashpad.cpp | 103 +++++++++++++++++++++++- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/interface/src/CrashHandler_Crashpad.cpp b/interface/src/CrashHandler_Crashpad.cpp index 900a296955..6ce8d170e2 100644 --- a/interface/src/CrashHandler_Crashpad.cpp +++ b/interface/src/CrashHandler_Crashpad.cpp @@ -16,11 +16,13 @@ #include #include +#include #include -#include -#include -#include +#include +#include +#include +#include #if defined(__clang__) @@ -59,6 +61,10 @@ static const QString CRASHPAD_HANDLER_NAME { "crashpad_handler" }; #ifdef Q_OS_WIN #include +#include + +void fatalCxxException(PEXCEPTION_POINTERS pExceptionInfo); + LONG WINAPI vectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) { if (!client) { @@ -70,8 +76,99 @@ LONG WINAPI vectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) { client->DumpAndCrash(pExceptionInfo); } + if (pExceptionInfo->ExceptionRecord->ExceptionCode == 0xE06D7363) { + fatalCxxException(pExceptionInfo); + client->DumpAndCrash(pExceptionInfo); + } + return EXCEPTION_CONTINUE_SEARCH; } + +#pragma pack(push, ehdata, 4) + +struct PMD_internal { + int mdisp; + int pdisp; + int vdisp; +}; + +struct ThrowInfo_internal { + __int32 attributes; + __int32 pmfnUnwind; // 32-bit RVA + __int32 pForwardCompat; // 32-bit RVA + __int32 pCatchableTypeArray; // 32-bit RVA +}; + +struct CatchableType_internal { + __int32 properties; + __int32 pType; // 32-bit RVA + PMD_internal thisDisplacement; + __int32 sizeOrOffset; + __int32 copyFunction; // 32-bit RVA +}; + +#pragma warning(disable : 4200) +struct CatchableTypeArray_internal { + int nCatchableTypes; + __int32 arrayOfCatchableTypes[0]; // 32-bit RVA +}; +#pragma warning(default : 4200) + +#pragma pack(pop, ehdata) + +// everything inside this function is extremely undocumented, attempting to extract +// the underlying C++ exception type (or at least its name) before throwing the whole +// mess at crashpad +void fatalCxxException(PEXCEPTION_POINTERS pExceptionInfo) { + PEXCEPTION_RECORD ExceptionRecord = pExceptionInfo->ExceptionRecord; + + if(ExceptionRecord->NumberParameters != 4 || ExceptionRecord->ExceptionInformation[0] != 0x19930520) { + // doesn't match expected parameter counts or magic numbers + return; + } + + //ULONG_PTR signature = ExceptionRecord->ExceptionInformation[0]; + void* pExceptionObject = reinterpret_cast(ExceptionRecord->ExceptionInformation[1]); // the object that generated the exception + ThrowInfo_internal* pThrowInfo = reinterpret_cast(ExceptionRecord->ExceptionInformation[2]); + ULONG_PTR moduleBase = ExceptionRecord->ExceptionInformation[3]; + if(moduleBase == 0 || pThrowInfo == NULL) { + return; // broken assumption + } + + // now we start breaking the pThrowInfo internal structure apart + if(pThrowInfo->pCatchableTypeArray == 0) { + return; // broken assumption + } + CatchableTypeArray_internal* pCatchableTypeArray = reinterpret_cast(moduleBase + pThrowInfo->pCatchableTypeArray); + if(pCatchableTypeArray->nCatchableTypes == 0 || pCatchableTypeArray->arrayOfCatchableTypes[0] == 0) { + return; // broken assumption + } + CatchableType_internal* pCatchableType = reinterpret_cast(moduleBase + pCatchableTypeArray->arrayOfCatchableTypes[0]); + if(pCatchableType->pType == 0) { + return; // broken assumption + } + const std::type_info* type = reinterpret_cast(moduleBase + pCatchableType->pType); + + // we're crashing, not really sure it matters who's currently holding the lock (although this could in theory really mess things up + annotationMutex.try_lock(); + crashpadAnnotations->SetKeyValue("thrownObject", type->name()); + + QString compatibleObjects; + for (int catchTypeIdx = 1; catchTypeIdx < pCatchableTypeArray->nCatchableTypes; catchTypeIdx++) { + CatchableType_internal* pCatchableSuperclassType = reinterpret_cast(moduleBase + pCatchableTypeArray->arrayOfCatchableTypes[catchTypeIdx]); + if (pCatchableSuperclassType->pType == 0) { + return; // broken assumption + } + const std::type_info* superclassType = reinterpret_cast(moduleBase + pCatchableSuperclassType->pType); + + if (!compatibleObjects.isEmpty()) { + compatibleObjects += ", "; + } + compatibleObjects += superclassType->name(); + } + crashpadAnnotations->SetKeyValue("thrownObjectLike", compatibleObjects.toStdString()); +} + #endif bool startCrashHandler(std::string appPath) {