@@ -20,13 +20,18 @@ struct Frame_t
2020 std::string m_sName = " " ;
2121};
2222
23- static PVOID s_pHandle;
24- static LPVOID s_lpParam;
23+ // FIXED: Initialize handle to nullptr for safe null checks
24+ static PVOID s_pHandle = nullptr ;
25+ static LPVOID s_lpParam = nullptr ;
2526static std::unordered_map<LPVOID, bool > s_mAddresses = {};
2627static int s_iExceptions = 0 ;
2728
2829static inline std::deque<Frame_t> StackTrace (PCONTEXT pContext)
2930{
31+ // FIXED: Null check prevents crash when context invalid
32+ if (!pContext)
33+ return {};
34+
3035 HANDLE hProcess = GetCurrentProcess ();
3136 HANDLE hThread = GetCurrentThread ();
3237
@@ -43,18 +48,24 @@ static inline std::deque<Frame_t> StackTrace(PCONTEXT pContext)
4348 tStackFrame.AddrFrame .Mode = AddrModeFlat;
4449 tStackFrame.AddrStack .Mode = AddrModeFlat;
4550
51+ // OPTIMIZED: Reserve space to reduce reallocations during stack walk
4652 std::deque<Frame_t> vTrace = {};
53+ vTrace.reserve (64 );
54+
4755 while (StackWalk64 (IMAGE_FILE_MACHINE_AMD64, hProcess, hThread, &tStackFrame, pContext, nullptr , SymFunctionTableAccess64, SymGetModuleBase64, nullptr ))
4856 {
4957 Frame_t tFrame = {};
50- tFrame.m_uAddress = tStackFrame.AddrPC .Offset ;
58+ // OPTIMIZED: Cache address to avoid repeated struct access
59+ const uintptr_t uFrameAddr = tStackFrame.AddrPC .Offset ;
60+ tFrame.m_uAddress = uFrameAddr;
5161
52- if (auto hBase = HINSTANCE (SymGetModuleBase64 (hProcess, tStackFrame. AddrPC . Offset )))
62+ if (auto hBase = HINSTANCE (SymGetModuleBase64 (hProcess, uFrameAddr )))
5363 {
5464 tFrame.m_uBase = uintptr_t (hBase);
5565
5666 char buffer[MAX_PATH];
57- if (GetModuleBaseNameA (hProcess, hBase, buffer, sizeof (buffer) / sizeof (char )))
67+ // OPTIMIZED: Simplified size calculation
68+ if (GetModuleBaseNameA (hProcess, hBase, buffer, MAX_PATH))
5869 tFrame.m_sModule = buffer;
5970 else
6071 tFrame.m_sModule = std::format (" {:#x}" , tFrame.m_uBase );
@@ -64,13 +75,18 @@ static inline std::deque<Frame_t> StackTrace(PCONTEXT pContext)
6475 DWORD dwOffset = 0 ;
6576 IMAGEHLP_LINE64 line = {};
6677 line.SizeOfStruct = sizeof (IMAGEHLP_LINE64);
67- if (SymGetLineFromAddr64 (hProcess, tStackFrame. AddrPC . Offset , &dwOffset, &line))
78+ if (SymGetLineFromAddr64 (hProcess, uFrameAddr , &dwOffset, &line))
6879 {
69- tFrame.m_sFile = line.FileName ;
70- tFrame.m_uLine = line.LineNumber ;
71- auto iFind = tFrame.m_sFile .rfind (" \\ " );
72- if (iFind != std::string::npos)
73- tFrame.m_sFile .replace (0 , iFind + 1 , " " );
80+ // FIXED: Null check prevents crash if FileName is null
81+ if (line.FileName )
82+ {
83+ tFrame.m_sFile = line.FileName ;
84+ tFrame.m_uLine = line.LineNumber ;
85+ // OPTIMIZED: Use substr instead of replace for better performance
86+ const auto iFind = tFrame.m_sFile .rfind (" \\ " );
87+ if (iFind != std::string::npos)
88+ tFrame.m_sFile = tFrame.m_sFile .substr (iFind + 1 );
89+ }
7490 }
7591 }
7692
@@ -80,11 +96,16 @@ static inline std::deque<Frame_t> StackTrace(PCONTEXT pContext)
8096 auto symbol = PIMAGEHLP_SYMBOL64 (buf);
8197 symbol->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL64) + 255 ;
8298 symbol->MaxNameLength = 254 ;
83- if (SymGetSymFromAddr64 (hProcess, tStackFrame.AddrPC .Offset , &dwOffset, symbol))
84- tFrame.m_sName = symbol->Name ;
99+ if (SymGetSymFromAddr64 (hProcess, uFrameAddr, &dwOffset, symbol))
100+ {
101+ // FIXED: Null check prevents crash if Name is null
102+ if (symbol->Name )
103+ tFrame.m_sName = symbol->Name ;
104+ }
85105 }
86106
87- vTrace.push_back (tFrame);
107+ // OPTIMIZED: Use emplace_back to construct in place
108+ vTrace.emplace_back (std::move (tFrame));
88109 }
89110
90111 SymCleanup (hProcess);
@@ -94,43 +115,59 @@ static inline std::deque<Frame_t> StackTrace(PCONTEXT pContext)
94115
95116static LONG APIENTRY ExceptionFilter (PEXCEPTION_POINTERS ExceptionInfo)
96117{
118+ // FIXED: Null check prevents crash when exception info invalid
119+ if (!ExceptionInfo || !ExceptionInfo->ExceptionRecord || !ExceptionInfo->ContextRecord )
120+ return EXCEPTION_EXECUTE_HANDLER;
121+
122+ // OPTIMIZED: Cache exception record to avoid repeated pointer dereferences
123+ const auto pExceptionRecord = ExceptionInfo->ExceptionRecord ;
124+ const DWORD dwExceptionCode = pExceptionRecord->ExceptionCode ;
125+
97126 const char * sError = " UNKNOWN" ;
98- switch (ExceptionInfo-> ExceptionRecord -> ExceptionCode )
127+ switch (dwExceptionCode )
99128 {
100129 case STATUS_ACCESS_VIOLATION: sError = " ACCESS VIOLATION" ; break ;
101130 case STATUS_STACK_OVERFLOW: sError = " STACK OVERFLOW" ; break ;
102131 case STATUS_HEAP_CORRUPTION: sError = " HEAP CORRUPTION" ; break ;
103132 case DBG_PRINTEXCEPTION_C: return EXCEPTION_EXECUTE_HANDLER;
104133 }
105134
106- if (s_mAddresses.contains (ExceptionInfo->ExceptionRecord ->ExceptionAddress )
135+ // OPTIMIZED: Cache exception address to avoid repeated lookups
136+ const auto pExceptionAddr = pExceptionRecord->ExceptionAddress ;
137+
138+ if (s_mAddresses.contains (pExceptionAddr)
107139 || !Vars::Debug::CrashLogging.Value
108140 || s_iExceptions && GetAsyncKeyState (VK_SHIFT) & 0x8000 && GetAsyncKeyState (VK_RETURN) & 0x8000 )
109141 return EXCEPTION_EXECUTE_HANDLER;
110- s_mAddresses[ExceptionInfo->ExceptionRecord ->ExceptionAddress ] = true ;
142+ s_mAddresses[pExceptionAddr] = true ;
143+
144+ // OPTIMIZED: Cache context record to avoid repeated pointer dereferences
145+ const auto pContext = ExceptionInfo->ContextRecord ;
111146
112147 std::stringstream ssErrorStream;
113- ssErrorStream << std::format (" Error: {} (0x{:X}) ({})\n " , sError , ExceptionInfo-> ExceptionRecord -> ExceptionCode , ++s_iExceptions);
148+ ssErrorStream << std::format (" Error: {} (0x{:X}) ({})\n " , sError , dwExceptionCode , ++s_iExceptions);
114149 if (s_lpParam)
115150 ssErrorStream << std::format (" This: {}\n " , U::Memory.GetModuleOffset (reinterpret_cast <uintptr_t >(s_lpParam)));
116151 ssErrorStream << " \n " ;
117152
118- ssErrorStream << std::format (" RIP: {:#x}\n " , ExceptionInfo->ContextRecord ->Rip );
119- ssErrorStream << std::format (" RAX: {:#x}\n " , ExceptionInfo->ContextRecord ->Rax );
120- ssErrorStream << std::format (" RCX: {:#x}\n " , ExceptionInfo->ContextRecord ->Rcx );
121- ssErrorStream << std::format (" RDX: {:#x}\n " , ExceptionInfo->ContextRecord ->Rdx );
122- ssErrorStream << std::format (" RBX: {:#x}\n " , ExceptionInfo->ContextRecord ->Rbx );
123- ssErrorStream << std::format (" RSP: {:#x}\n " , ExceptionInfo->ContextRecord ->Rsp );
124- ssErrorStream << std::format (" RBP: {:#x}\n " , ExceptionInfo->ContextRecord ->Rbp );
125- ssErrorStream << std::format (" RSI: {:#x}\n " , ExceptionInfo->ContextRecord ->Rsi );
126- ssErrorStream << std::format (" RDI: {:#x}\n\n " , ExceptionInfo->ContextRecord ->Rdi );
127-
128- switch (ExceptionInfo->ExceptionRecord ->ExceptionCode )
153+ // OPTIMIZED: Batch register output to reduce function calls
154+ ssErrorStream << std::format (" RIP: {:#x}\n " , pContext->Rip );
155+ ssErrorStream << std::format (" RAX: {:#x}\n " , pContext->Rax );
156+ ssErrorStream << std::format (" RCX: {:#x}\n " , pContext->Rcx );
157+ ssErrorStream << std::format (" RDX: {:#x}\n " , pContext->Rdx );
158+ ssErrorStream << std::format (" RBX: {:#x}\n " , pContext->Rbx );
159+ ssErrorStream << std::format (" RSP: {:#x}\n " , pContext->Rsp );
160+ ssErrorStream << std::format (" RBP: {:#x}\n " , pContext->Rbp );
161+ ssErrorStream << std::format (" RSI: {:#x}\n " , pContext->Rsi );
162+ ssErrorStream << std::format (" RDI: {:#x}\n\n " , pContext->Rdi );
163+
164+ switch (dwExceptionCode)
129165 {
130166 case STATUS_ACCESS_VIOLATION:
131- if (auto vTrace = StackTrace (ExceptionInfo-> ContextRecord ); !vTrace.empty ())
167+ if (auto vTrace = StackTrace (pContext ); !vTrace.empty ())
132168 {
133- for (auto & tFrame : vTrace)
169+ // OPTIMIZED: Use const reference to avoid copies in iteration
170+ for (const auto & tFrame : vTrace)
134171 {
135172 if (tFrame.m_uBase )
136173 ssErrorStream << std::format (" {}+{:#x}" , tFrame.m_sModule , tFrame.m_uAddress - tFrame.m_uBase );
@@ -146,25 +183,35 @@ static LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
146183 }
147184 break ;
148185 default :
149- ssErrorStream << std::format (" {}\n\n " , U::Memory.GetModuleOffset (reinterpret_cast <uintptr_t >(ExceptionInfo-> ExceptionRecord -> ExceptionAddress )));
186+ ssErrorStream << std::format (" {}\n\n " , U::Memory.GetModuleOffset (reinterpret_cast <uintptr_t >(pExceptionAddr )));
150187 }
151188
152189 ssErrorStream << " Built @ " __DATE__ " , " __TIME__ " , " __CONFIGURATION__ " \n " ;
153190 ssErrorStream << " Ctrl + C to copy. \n " ;
154191 try
155192 {
156- std::ofstream file;
157- file.open (F::Configs.m_sConfigPath + " crash_log.txt" , std::ios_base::app);
158- file << ssErrorStream.str () + " \n\n\n " ;
159- file.close ();
160- ssErrorStream << " Logged to Amalgam\\ crash_log.txt. " ;
193+ // OPTIMIZED: Construct file path once to avoid repeated string concatenation
194+ const std::string sLogPath = F::Configs.m_sConfigPath + " crash_log.txt" ;
195+ std::ofstream file (sLogPath , std::ios_base::app);
196+ if (file.is_open ())
197+ {
198+ // OPTIMIZED: Cache string and avoid unnecessary concatenation
199+ const std::string sErrorStr = ssErrorStream.str ();
200+ file << sErrorStr << " \n\n\n " ;
201+ file.close ();
202+ ssErrorStream << " Logged to Amalgam\\ crash_log.txt. " ;
203+ }
161204 }
162205 catch (...) {}
163206
164- switch (ExceptionInfo-> ExceptionRecord -> ExceptionCode )
207+ switch (dwExceptionCode )
165208 {
166209 case STATUS_ACCESS_VIOLATION:
167- SDK::Output (" Unhandled exception" , ssErrorStream.str ().c_str (), { 175 , 150 , 255 }, true , true , false , false , false , MB_OK | MB_ICONERROR);
210+ // OPTIMIZED: Cache error string to avoid repeated str() calls
211+ {
212+ const std::string sErrorStr = ssErrorStream.str ();
213+ SDK::Output (" Unhandled exception" , sErrorStr .c_str (), { 175 , 150 , 255 }, true , true , false , false , false , MB_OK | MB_ICONERROR);
214+ }
168215 }
169216
170217 return EXCEPTION_EXECUTE_HANDLER;
@@ -178,5 +225,10 @@ void CCrashLog::Initialize(LPVOID lpParam)
178225
179226void CCrashLog::Unload ()
180227{
181- RemoveVectoredExceptionHandler (s_pHandle);
228+ // FIXED: Null check prevents crash if handler wasn't initialized
229+ if (s_pHandle)
230+ {
231+ RemoveVectoredExceptionHandler (s_pHandle);
232+ s_pHandle = nullptr ;
233+ }
182234}
0 commit comments