2020#include < SharedUtil.Detours.h>
2121#include < SharedUtil.Misc.h>
2222#include < SharedUtil.Memory.h>
23+ #include " ../Shared/sdk/CrashTelemetry.h"
2324
2425#include < algorithm>
2526#include < array>
2627#include < atomic>
2728#include < chrono>
2829#include < cctype>
2930#include < cstdint>
31+ #include < cstring>
3032#include < exception>
3133#include < errno.h>
3234#include < filesystem>
4446#include < string_view>
4547#include < variant>
4648#include < vector>
49+ #if defined(_MSC_VER)
50+ #include < new.h>
51+ #endif
4752
4853#if defined(_MSC_VER)
4954 #include < corecrt.h>
@@ -94,6 +99,16 @@ inline std::atomic<DWORD> g_initializationPhase{INIT_PHASE_MINIMAL};
9499
95100using CrashHandlerResult = std::variant<std::monostate, std::string, DWORD, std::exception_ptr>;
96101
102+ #if defined(__cplusplus)
103+ [[noreturn]] void __cdecl CppNewHandler () noexcept ;
104+ #endif
105+
106+ #if defined(_MSC_VER)
107+ static int __cdecl CppNewHandlerBridge (size_t size) noexcept ;
108+ #else
109+ static void CppNewHandlerBridge () noexcept ;
110+ #endif
111+
97112[[nodiscard]] BOOL BUGSUTIL_DLLINTERFACE __stdcall IsFatalException (DWORD exceptionCode) noexcept
98113{
99114 switch (exceptionCode)
@@ -173,13 +188,21 @@ static void StoreBasicExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
173188 return ;
174189 }
175190
176- g_lastExceptionInfo = ENHANCED_EXCEPTION_INFO{
191+ ENHANCED_EXCEPTION_INFO info {
177192 .exceptionCode = pException->ExceptionRecord ->ExceptionCode ,
178193 .exceptionAddress = pException->ExceptionRecord ->ExceptionAddress ,
179194 .timestamp = std::chrono::system_clock::now (),
180195 .threadId = GetCurrentThreadId (),
181196 .processId = GetCurrentProcessId ()
182197 };
198+
199+ const auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote ();
200+ if (!telemetryNote.empty ())
201+ {
202+ info.additionalInfo = telemetryNote;
203+ }
204+
205+ g_lastExceptionInfo = info;
183206 }
184207 catch (...)
185208 {
@@ -495,6 +518,12 @@ static void LogEnhancedExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
495518 case EXCEPTION_GUARD_PAGE:
496519 info.exceptionType = " SEH:GuardPage" ;
497520 break ;
521+ case CUSTOM_EXCEPTION_CODE_OOM:
522+ info.exceptionType = " User:OutOfMemory" ;
523+ break ;
524+ case CUSTOM_EXCEPTION_CODE_WATCHDOG_TIMEOUT:
525+ info.exceptionType = " User:WatchdogTimeout" ;
526+ break ;
498527 default :
499528 if (info.exceptionCode >= 0xC0000000 && info.exceptionCode <= 0xCFFFFFFF )
500529 {
@@ -513,6 +542,15 @@ static void LogEnhancedExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
513542
514543 info.exceptionDescription = GetExceptionCodeDescription (info.exceptionCode );
515544
545+ if (auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote (); !telemetryNote.empty ())
546+ {
547+ if (!info.additionalInfo .empty ())
548+ {
549+ info.additionalInfo .push_back (' \n ' );
550+ }
551+ info.additionalInfo += telemetryNote;
552+ }
553+
516554 g_lastExceptionInfo = info;
517555 }
518556 catch (...)
@@ -522,7 +560,16 @@ static void LogEnhancedExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
522560 }
523561}
524562
525- static std::variant<DWORD, std::string> HandleExceptionModern (_EXCEPTION_POINTERS* pException)
563+ static void CaptureAllocationTelemetry (_EXCEPTION_POINTERS* pException) noexcept
564+ {
565+ if (pException == nullptr || pException->ExceptionRecord == nullptr )
566+ return ;
567+
568+ StoreBasicExceptionInfo (pException);
569+ LogEnhancedExceptionInfo (pException);
570+ }
571+
572+ static std::variant<DWORD, std::string> HandleExceptionModern (_EXCEPTION_POINTERS* pException) noexcept
526573{
527574 if (pException == nullptr || pException->ExceptionRecord == nullptr )
528575 {
@@ -625,7 +672,12 @@ static std::mutex g_handlerStateMutex;
625672static std::atomic<PFNCHFILTFN> g_pfnCrashCallback{nullptr };
626673static std::atomic<LPTOP_LEVEL_EXCEPTION_FILTER> g_pfnOrigFilt{nullptr };
627674static std::atomic<std::terminate_handler> g_pfnOrigTerminate{nullptr };
675+ #if defined(_MSC_VER)
676+ using CrtNewHandler = int (__cdecl*)(size_t );
677+ static std::atomic<CrtNewHandler> g_pfnOrigNewHandler{nullptr };
678+ #else
628679static std::atomic<std::new_handler> g_pfnOrigNewHandler{nullptr };
680+ #endif
629681static std::atomic<decltype (&SetUnhandledExceptionFilter)> g_pfnKernelSetUnhandledExceptionFilter{nullptr };
630682static decltype (&SetUnhandledExceptionFilter) g_kernelSetUnhandledExceptionFilterTrampoline = nullptr;
631683
@@ -641,10 +693,45 @@ static std::atomic<bool> g_symbolsInitialized{false};
641693static std::atomic<HANDLE> g_symbolProcess{nullptr };
642694static std::mutex g_symbolMutex;
643695
696+ #if defined(_MSC_VER)
697+ static int __cdecl CppNewHandlerBridge (size_t size) noexcept
698+ {
699+ const auto telemetry = CrashTelemetry::CaptureContext ();
700+ if ((!telemetry.hasData || telemetry.requestedSize == 0 ) && size > 0 )
701+ {
702+ CrashTelemetry::SetAllocationContext (size, nullptr , " operator new" , " std::new_handler" );
703+ }
704+
705+ if (auto previous = g_pfnOrigNewHandler.load (std::memory_order_acquire))
706+ {
707+ return previous (size);
708+ }
709+
710+ CppNewHandler ();
711+ return 0 ;
712+ }
713+ #else
714+ static void CppNewHandlerBridge () noexcept
715+ {
716+ const auto telemetry = CrashTelemetry::CaptureContext ();
717+ if (!telemetry.hasData )
718+ {
719+ CrashTelemetry::SetAllocationContext (0 , nullptr , " operator new" , " std::new_handler" );
720+ }
721+
722+ if (auto previous = g_pfnOrigNewHandler.load (std::memory_order_acquire))
723+ {
724+ previous ();
725+ return ;
726+ }
727+
728+ CppNewHandler ();
729+ }
730+ #endif
731+
644732LONG __stdcall CrashHandlerExceptionFilter (EXCEPTION_POINTERS* pExPtrs);
645733
646734[[noreturn]] void __cdecl CppTerminateHandler () noexcept ;
647- [[noreturn]] void __cdecl CppNewHandler () noexcept ;
648735void __cdecl AbortSignalHandler (int signal) noexcept ;
649736[[noreturn]] void __cdecl PureCallHandler () noexcept ;
650737
@@ -766,6 +853,8 @@ void __cdecl AbortSignalHandler([[maybe_unused]] int signal) noexcept
766853 exPtrs.ExceptionRecord = &exRecord;
767854 exPtrs.ContextRecord = &ctx;
768855
856+ CaptureAllocationTelemetry (&exPtrs);
857+
769858 PFNCHFILTFN callback = g_pfnCrashCallback.load (std::memory_order_acquire);
770859
771860 if (callback != nullptr )
@@ -804,13 +893,19 @@ void __cdecl AbortSignalHandler([[maybe_unused]] int signal) noexcept
804893 LogHandlerEvent (DEBUG_PREFIX_PURECALL.data (), " Pure virtual function call detected" );
805894 SafeDebugOutput (DEBUG_SEPARATOR);
806895
807- EXCEPTION_RECORD* pExRecord{nullptr };
808- CONTEXT* pCtx{nullptr };
896+ EXCEPTION_RECORD* pExRecord{nullptr };
897+ CONTEXT* pCtx{nullptr };
809898 EXCEPTION_POINTERS exPtrs{};
810899
900+ const bool haveContext = BuildExceptionContext (exPtrs, pExRecord, pCtx, EXCEPTION_NONCONTINUABLE_EXCEPTION);
901+ if (haveContext)
902+ {
903+ CaptureAllocationTelemetry (&exPtrs);
904+ }
905+
811906 PFNCHFILTFN callback = g_pfnCrashCallback.load (std::memory_order_acquire);
812907
813- if (callback != nullptr && BuildExceptionContext (exPtrs, pExRecord, pCtx, EXCEPTION_NONCONTINUABLE_EXCEPTION) )
908+ if (callback != nullptr && haveContext )
814909 {
815910 LogHandlerEvent (DEBUG_PREFIX_PURECALL.data (), " Calling crash handler callback" );
816911
@@ -867,7 +962,11 @@ class CleanUpCrashHandler
867962
868963 if (auto newHandler = g_pfnOrigNewHandler.exchange (nullptr , std::memory_order_acq_rel); newHandler != nullptr )
869964 {
965+ #if defined(_MSC_VER)
966+ _set_new_handler (newHandler);
967+ #else
870968 std::set_new_handler (newHandler);
969+ #endif
871970 }
872971
873972 if (auto abortHandler = g_pfnOrigAbortHandler.exchange (nullptr , std::memory_order_acq_rel); abortHandler != nullptr )
@@ -1332,7 +1431,11 @@ static void InstallCppHandlers() noexcept
13321431
13331432 if (g_pfnOrigNewHandler.load (std::memory_order_acquire) == nullptr )
13341433 {
1335- std::new_handler previous = std::set_new_handler (CppNewHandler);
1434+ #if defined(_MSC_VER)
1435+ CrtNewHandler previous = _set_new_handler (CppNewHandlerBridge);
1436+ #else
1437+ std::new_handler previous = std::set_new_handler (CppNewHandlerBridge);
1438+ #endif
13361439 g_pfnOrigNewHandler.store (previous, std::memory_order_release);
13371440 SafeDebugOutput (" CrashHandler: C++ new handler installed\n " );
13381441 }
@@ -1903,7 +2006,11 @@ static void UninstallCrashHandlers() noexcept
19032006
19042007 if (auto newHandler = g_pfnOrigNewHandler.exchange (nullptr , std::memory_order_acq_rel); newHandler != nullptr )
19052008 {
2009+ #if defined(_MSC_VER)
2010+ _set_new_handler (newHandler);
2011+ #else
19062012 std::set_new_handler (newHandler);
2013+ #endif
19072014 }
19082015
19092016 if (auto abortHandler = g_pfnOrigAbortHandler.exchange (nullptr , std::memory_order_acq_rel); abortHandler != nullptr )
@@ -2004,13 +2111,24 @@ static bool BuildExceptionContext(EXCEPTION_POINTERS& outExPtrs, EXCEPTION_RECOR
20042111
20052112 SafeDebugOutput (DEBUG_SEPARATOR);
20062113
2114+ if (auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote (); !telemetryNote.empty ())
2115+ {
2116+ SafeDebugPrintPrefixed (DEBUG_PREFIX_CPP, " %s\n " , telemetryNote.c_str ());
2117+ }
2118+
20072119 EXCEPTION_RECORD* pExRecord = nullptr ;
20082120 CONTEXT* pCtx = nullptr ;
20092121 EXCEPTION_POINTERS exPtrs{};
20102122
2123+ const bool haveContext = BuildExceptionContext (exPtrs, pExRecord, pCtx, CPP_EXCEPTION_CODE);
2124+ if (haveContext)
2125+ {
2126+ CaptureAllocationTelemetry (&exPtrs);
2127+ }
2128+
20112129 PFNCHFILTFN callback = g_pfnCrashCallback.load (std::memory_order_acquire);
20122130
2013- if (callback != nullptr && BuildExceptionContext (exPtrs, pExRecord, pCtx, CPP_EXCEPTION_CODE) )
2131+ if (callback != nullptr && haveContext )
20142132 {
20152133 SafeDebugPrintPrefixed (DEBUG_PREFIX_CPP, " Calling crash handler callback\n " );
20162134
@@ -2082,6 +2200,12 @@ static void ReportCurrentCppException() noexcept
20822200 SafeDebugOutput (" C++ NEW HANDLER: Memory allocation failed\n " );
20832201 SafeDebugOutput (DEBUG_SEPARATOR);
20842202
2203+ if (auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote (); !telemetryNote.empty ())
2204+ {
2205+ SafeDebugOutput (telemetryNote.c_str ());
2206+ SafeDebugOutput (" \n " );
2207+ }
2208+
20852209 std::terminate ();
20862210}
20872211
0 commit comments