1919#include < SharedUtil.Detours.h>
2020#include < SharedUtil.Misc.h>
2121#include < SharedUtil.Memory.h>
22+ #include " ../Shared/sdk/CrashTelemetry.h"
2223
2324#include < algorithm>
2425#include < array>
2526#include < atomic>
2627#include < chrono>
2728#include < cctype>
2829#include < cstdint>
30+ #include < cstring>
2931#include < exception>
3032#include < errno.h>
3133#include < intrin.h>
4042#include < string_view>
4143#include < variant>
4244#include < vector>
45+ #if defined(_MSC_VER)
46+ #include < new.h>
47+ #endif
4348
4449#if defined(_MSC_VER)
4550 #include < corecrt.h>
@@ -90,6 +95,16 @@ inline std::atomic<DWORD> g_initializationPhase{INIT_PHASE_MINIMAL};
9095
9196using CrashHandlerResult = std::variant<std::monostate, std::string, DWORD, std::exception_ptr>;
9297
98+ #if defined(__cplusplus)
99+ [[noreturn]] void __cdecl CppNewHandler () noexcept ;
100+ #endif
101+
102+ #if defined(_MSC_VER)
103+ static int __cdecl CppNewHandlerBridge (size_t size) noexcept ;
104+ #else
105+ static void CppNewHandlerBridge () noexcept ;
106+ #endif
107+
93108[[nodiscard]] BOOL BUGSUTIL_DLLINTERFACE __stdcall IsFatalException (DWORD exceptionCode) noexcept
94109{
95110 switch (exceptionCode)
@@ -175,6 +190,11 @@ static void StoreBasicExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
175190 info.timestamp = std::chrono::system_clock::now ();
176191 info.threadId = GetCurrentThreadId ();
177192 info.processId = GetCurrentProcessId ();
193+ const auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote ();
194+ if (!telemetryNote.empty ())
195+ {
196+ info.additionalInfo = telemetryNote;
197+ }
178198 g_lastExceptionInfo = info;
179199 }
180200 catch (...)
@@ -491,6 +511,12 @@ static void LogEnhancedExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
491511 case EXCEPTION_GUARD_PAGE:
492512 info.exceptionType = " SEH:GuardPage" ;
493513 break ;
514+ case CUSTOM_EXCEPTION_CODE_OOM:
515+ info.exceptionType = " User:OutOfMemory" ;
516+ break ;
517+ case CUSTOM_EXCEPTION_CODE_WATCHDOG_TIMEOUT:
518+ info.exceptionType = " User:WatchdogTimeout" ;
519+ break ;
494520 default :
495521 if (info.exceptionCode >= 0xC0000000 && info.exceptionCode <= 0xCFFFFFFF )
496522 {
@@ -509,6 +535,15 @@ static void LogEnhancedExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
509535
510536 info.exceptionDescription = GetExceptionCodeDescription (info.exceptionCode );
511537
538+ if (auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote (); !telemetryNote.empty ())
539+ {
540+ if (!info.additionalInfo .empty ())
541+ {
542+ info.additionalInfo .push_back (' \n ' );
543+ }
544+ info.additionalInfo += telemetryNote;
545+ }
546+
512547 g_lastExceptionInfo = info;
513548 }
514549 catch (...)
@@ -518,6 +553,15 @@ static void LogEnhancedExceptionInfo(_EXCEPTION_POINTERS* pException) noexcept
518553 }
519554}
520555
556+ static void CaptureAllocationTelemetry (_EXCEPTION_POINTERS* pException) noexcept
557+ {
558+ if (pException == nullptr || pException->ExceptionRecord == nullptr )
559+ return ;
560+
561+ StoreBasicExceptionInfo (pException);
562+ LogEnhancedExceptionInfo (pException);
563+ }
564+
521565static std::variant<DWORD, std::string> HandleExceptionModern (_EXCEPTION_POINTERS* pException) noexcept
522566{
523567 if (pException == nullptr || pException->ExceptionRecord == nullptr )
@@ -621,7 +665,12 @@ static std::mutex g_handlerStateMutex;
621665static std::atomic<PFNCHFILTFN> g_pfnCrashCallback{nullptr };
622666static std::atomic<LPTOP_LEVEL_EXCEPTION_FILTER> g_pfnOrigFilt{nullptr };
623667static std::atomic<std::terminate_handler> g_pfnOrigTerminate{nullptr };
668+ #if defined(_MSC_VER)
669+ using CrtNewHandler = int (__cdecl*)(size_t );
670+ static std::atomic<CrtNewHandler> g_pfnOrigNewHandler{nullptr };
671+ #else
624672static std::atomic<std::new_handler> g_pfnOrigNewHandler{nullptr };
673+ #endif
625674static std::atomic<decltype (&SetUnhandledExceptionFilter)> g_pfnKernelSetUnhandledExceptionFilter{nullptr };
626675static decltype (&SetUnhandledExceptionFilter) g_kernelSetUnhandledExceptionFilterTrampoline = nullptr;
627676
@@ -633,10 +682,45 @@ static std::atomic<bool> g_bInPureCallHandler{false};
633682static std::atomic<bool > g_bInTerminateHandler{false };
634683static std::atomic<bool > g_bInNewHandler{false };
635684
685+ #if defined(_MSC_VER)
686+ static int __cdecl CppNewHandlerBridge (size_t size) noexcept
687+ {
688+ const auto telemetry = CrashTelemetry::CaptureContext ();
689+ if ((!telemetry.hasData || telemetry.requestedSize == 0 ) && size > 0 )
690+ {
691+ CrashTelemetry::SetAllocationContext (size, nullptr , " operator new" , " std::new_handler" );
692+ }
693+
694+ if (auto previous = g_pfnOrigNewHandler.load (std::memory_order_acquire))
695+ {
696+ return previous (size);
697+ }
698+
699+ CppNewHandler ();
700+ return 0 ;
701+ }
702+ #else
703+ static void CppNewHandlerBridge () noexcept
704+ {
705+ const auto telemetry = CrashTelemetry::CaptureContext ();
706+ if (!telemetry.hasData )
707+ {
708+ CrashTelemetry::SetAllocationContext (0 , nullptr , " operator new" , " std::new_handler" );
709+ }
710+
711+ if (auto previous = g_pfnOrigNewHandler.load (std::memory_order_acquire))
712+ {
713+ previous ();
714+ return ;
715+ }
716+
717+ CppNewHandler ();
718+ }
719+ #endif
720+
636721LONG __stdcall CrashHandlerExceptionFilter (EXCEPTION_POINTERS* pExPtrs);
637722
638723[[noreturn]] void __cdecl CppTerminateHandler () noexcept ;
639- [[noreturn]] void __cdecl CppNewHandler () noexcept ;
640724void __cdecl AbortSignalHandler (int signal) noexcept ;
641725[[noreturn]] void __cdecl PureCallHandler () noexcept ;
642726
@@ -758,6 +842,8 @@ void __cdecl AbortSignalHandler([[maybe_unused]] int signal) noexcept
758842 exPtrs.ExceptionRecord = &exRecord;
759843 exPtrs.ContextRecord = &ctx;
760844
845+ CaptureAllocationTelemetry (&exPtrs);
846+
761847 PFNCHFILTFN callback = g_pfnCrashCallback.load (std::memory_order_acquire);
762848
763849 if (callback != nullptr )
@@ -796,13 +882,19 @@ void __cdecl AbortSignalHandler([[maybe_unused]] int signal) noexcept
796882 LogHandlerEvent (DEBUG_PREFIX_PURECALL.data (), " Pure virtual function call detected" );
797883 SafeDebugOutput (DEBUG_SEPARATOR);
798884
799- EXCEPTION_RECORD* pExRecord{nullptr };
800- CONTEXT* pCtx{nullptr };
885+ EXCEPTION_RECORD* pExRecord{nullptr };
886+ CONTEXT* pCtx{nullptr };
801887 EXCEPTION_POINTERS exPtrs{};
802888
889+ const bool haveContext = BuildExceptionContext (exPtrs, pExRecord, pCtx, EXCEPTION_NONCONTINUABLE_EXCEPTION);
890+ if (haveContext)
891+ {
892+ CaptureAllocationTelemetry (&exPtrs);
893+ }
894+
803895 PFNCHFILTFN callback = g_pfnCrashCallback.load (std::memory_order_acquire);
804896
805- if (callback != nullptr && BuildExceptionContext (exPtrs, pExRecord, pCtx, EXCEPTION_NONCONTINUABLE_EXCEPTION) )
897+ if (callback != nullptr && haveContext )
806898 {
807899 LogHandlerEvent (DEBUG_PREFIX_PURECALL.data (), " Calling crash handler callback" );
808900
@@ -850,7 +942,11 @@ class CleanUpCrashHandler
850942
851943 if (auto newHandler = g_pfnOrigNewHandler.exchange (nullptr , std::memory_order_seq_cst); newHandler != nullptr )
852944 {
945+ #if defined(_MSC_VER)
946+ _set_new_handler (newHandler);
947+ #else
853948 std::set_new_handler (newHandler);
949+ #endif
854950 }
855951
856952 if (auto abortHandler = g_pfnOrigAbortHandler.exchange (nullptr , std::memory_order_seq_cst); abortHandler != nullptr )
@@ -985,7 +1081,11 @@ static void InstallCppHandlers() noexcept
9851081
9861082 if (g_pfnOrigNewHandler.load (std::memory_order_acquire) == nullptr )
9871083 {
988- std::new_handler previous = std::set_new_handler (CppNewHandler);
1084+ #if defined(_MSC_VER)
1085+ CrtNewHandler previous = _set_new_handler (CppNewHandlerBridge);
1086+ #else
1087+ std::new_handler previous = std::set_new_handler (CppNewHandlerBridge);
1088+ #endif
9891089 g_pfnOrigNewHandler.store (previous, std::memory_order_release);
9901090 SafeDebugOutput (" CrashHandler: C++ new handler installed\n " );
9911091 }
@@ -1468,7 +1568,11 @@ static void UninstallCrashHandlers() noexcept
14681568
14691569 if (auto newHandler = g_pfnOrigNewHandler.exchange (nullptr , std::memory_order_acq_rel); newHandler != nullptr )
14701570 {
1571+ #if defined(_MSC_VER)
1572+ _set_new_handler (newHandler);
1573+ #else
14711574 std::set_new_handler (newHandler);
1575+ #endif
14721576 }
14731577
14741578 if (auto abortHandler = g_pfnOrigAbortHandler.exchange (nullptr , std::memory_order_acq_rel); abortHandler != nullptr )
@@ -1569,13 +1673,24 @@ static bool BuildExceptionContext(EXCEPTION_POINTERS& outExPtrs, EXCEPTION_RECOR
15691673
15701674 SafeDebugOutput (DEBUG_SEPARATOR);
15711675
1676+ if (auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote (); !telemetryNote.empty ())
1677+ {
1678+ SafeDebugPrintPrefixed (DEBUG_PREFIX_CPP, " %s\n " , telemetryNote.c_str ());
1679+ }
1680+
15721681 EXCEPTION_RECORD* pExRecord = nullptr ;
15731682 CONTEXT* pCtx = nullptr ;
15741683 EXCEPTION_POINTERS exPtrs{};
15751684
1685+ const bool haveContext = BuildExceptionContext (exPtrs, pExRecord, pCtx, CPP_EXCEPTION_CODE);
1686+ if (haveContext)
1687+ {
1688+ CaptureAllocationTelemetry (&exPtrs);
1689+ }
1690+
15761691 PFNCHFILTFN callback = g_pfnCrashCallback.load (std::memory_order_acquire);
15771692
1578- if (callback != nullptr && BuildExceptionContext (exPtrs, pExRecord, pCtx, CPP_EXCEPTION_CODE) )
1693+ if (callback != nullptr && haveContext )
15791694 {
15801695 SafeDebugPrintPrefixed (DEBUG_PREFIX_CPP, " Calling crash handler callback\n " );
15811696
@@ -1647,6 +1762,12 @@ static void ReportCurrentCppException() noexcept
16471762 SafeDebugOutput (" C++ NEW HANDLER: Memory allocation failed\n " );
16481763 SafeDebugOutput (DEBUG_SEPARATOR);
16491764
1765+ if (auto telemetryNote = CrashTelemetry::BuildAllocationTelemetryNote (); !telemetryNote.empty ())
1766+ {
1767+ SafeDebugOutput (telemetryNote.c_str ());
1768+ SafeDebugOutput (" \n " );
1769+ }
1770+
16501771 std::terminate ();
16511772}
16521773
0 commit comments