CppCommon  1.0.4.1
C++ Common Library
exceptions_handler.cpp
Go to the documentation of this file.
1 
10 
11 #include "filesystem/path.h"
12 #include "system/stack_trace.h"
13 #include "time/timestamp.h"
14 #include "utility/resource.h"
16 
17 #include <cstring>
18 #include <exception>
19 #include <iostream>
20 
21 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
22 #include "string/format.h"
23 #include "utility/countof.h"
24 #include <signal.h>
25 #include <unistd.h>
26 #elif defined(_WIN32) || defined(_WIN64)
27 #if defined(_MSC_VER)
28 #include <intrin.h>
29 #endif
30 #include <csignal>
31 #include <new.h>
32 #include <windows.h>
33 #if defined(DBGHELP_SUPPORT)
34 #include "string/format.h"
35 #if defined(_MSC_VER)
36 #pragma warning(push)
37 #pragma warning(disable:4091) // C4091: 'keyword' : ignored on left of 'type' when no variable is declared
38 #endif
39 #include <dbghelp.h>
40 #if defined(_MSC_VER)
41 #pragma warning(pop)
42 #endif
43 #endif
44 #endif
45 
46 namespace CppCommon {
47 
49 
50 class ExceptionsHandler::Impl
51 {
52 public:
53  Impl() : _initialized(false), _handler(ExceptionsHandler::Impl::DefaultHandler) {}
54 
55  static ExceptionsHandler::Impl& GetInstance()
56  { return ExceptionsHandler::GetInstance().impl(); }
57 
58  void SetupHandler(const std::function<void (const SystemException&, const StackTrace&)>& handler)
59  {
60  assert((handler) && "Exceptions handler function must be valid!");
61  if (!handler)
62  return;
63 
64  _handler = handler;
65  }
66 
67  void SetupProcess()
68  {
69  // Check for double initialization
70  if (_initialized)
71  return;
72 
73 #if defined(_WIN32) || defined(_WIN64)
74  // Install top-level SEH handler
75  SetUnhandledExceptionFilter(SehHandler);
76 
77 #if defined(_MSC_VER)
78  // Catch pure virtual function calls
79  // Because there is one _purecall_handler for the whole process,
80  // calling this function immediately impacts all threads. The last
81  // caller on any thread sets the handler.
82  // http://msdn.microsoft.com/en-us/library/t296ys27.aspx
83  _set_purecall_handler(PureCallHandler);
84 
85  // Catch new operator memory allocation exceptions
86  _set_new_handler(NewHandler);
87 
88  // Catch invalid parameter exceptions
89  _set_invalid_parameter_handler(InvalidParameterHandler);
90 
91  // Set up C++ signal handlers
92  _set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT);
93 #endif
94 
95  // Catch an abnormal program termination
96  signal(SIGABRT, SigabrtHandler);
97 
98  // Catch an illegal instruction error
99  signal(SIGINT, SigintHandler);
100 
101  // Catch a termination request
102  signal(SIGTERM, SigtermHandler);
103 #elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
104  // Prepare signal action structure
105  struct sigaction sa;
106  memset(&sa, 0, sizeof(sa));
107  sa.sa_sigaction = SignalHandler;
108  sa.sa_flags = SA_SIGINFO;
109 
110  // Define signals to catch
111  int signals[] =
112  {
113  SIGABRT,
114  SIGALRM,
115  SIGBUS,
116  SIGFPE,
117  SIGHUP,
118  SIGILL,
119  SIGINT,
120  SIGPIPE,
121  SIGPROF,
122  SIGQUIT,
123  SIGSEGV,
124  SIGSYS,
125  SIGTERM,
126  SIGXCPU,
127  SIGXFSZ
128  };
129 
130  // Setup corresponding signals handlers
131  for (size_t i = 0; i < countof(signals); ++i)
132  {
133  int result = sigaction(signals[i], &sa, nullptr);
134  if (result != 0)
135  throwex SystemException(format("Failed to setup signal handler - {}", signals[i]));
136  }
137 #endif
138 
139  _initialized = true;
140  }
141 
142  static void SetupThread()
143  {
144 #if defined(_WIN32) || defined(_WIN64)
145 #if defined(_MSC_VER)
146  // Catch std::terminate() calls
147  // In a multithreaded environment, terminate functions are maintained
148  // separately for each thread. Each new thread needs to install its own
149  // terminate function. Thus, each thread is in charge of its own termination handling.
150  // http://msdn.microsoft.com/en-us/library/t6fk7h29.aspx
151  std::set_terminate(TerminateHandler);
152 
153 #if (__cplusplus < 201703L)
154  // Catch std::unexpected() calls
155  // In a multithreaded environment, unexpected functions are maintained
156  // separately for each thread. Each new thread needs to install its own
157  // unexpected function. Thus, each thread is in charge of its own unexpected handling.
158  // http://msdn.microsoft.com/en-us/library/h46t5b69.aspx
159  std::set_unexpected(UnexpectedHandler);
160 #endif
161 #endif
162 
163  // Catch a floating point exception
164  typedef void (*sigh)(int);
165  signal(SIGFPE, (sigh)SigfpeHandler);
166 
167  // Catch an illegal instruction
168  signal(SIGILL, SigillHandler);
169 
170  // Catch an illegal storage access error
171  signal(SIGSEGV, SigsegvHandler);
172 #endif
173  }
174 
175 private:
176  // Initialization flag for the current process
177  bool _initialized;
178  // Exception handler function
179  std::function<void (const SystemException&, const StackTrace&)> _handler;
180 
181  // Default exception handler function
182  static void DefaultHandler(const SystemException& exception, const StackTrace& trace)
183  {
184  std::cerr << exception;
185  std::cerr << "Stack trace:" << std::endl;
186  std::cerr << trace;
187  }
188 
189 #if defined(_WIN32) || defined(_WIN64)
190 
191  // Structured exception handler
192  static LONG WINAPI SehHandler(PEXCEPTION_POINTERS pExceptionPtrs)
193  {
194  // Output error
195  GetInstance()._handler(__LOCATION__ + SystemException("Unhandled SEH exception"), StackTrace(1));
196 
197  // Write dump file
198  CreateDumpFile(pExceptionPtrs);
199 
200  // Terminate process
201  TerminateProcess(GetCurrentProcess(), 1);
202 
203  // Unreacheable code
204  return EXCEPTION_EXECUTE_HANDLER;
205  }
206 
207 #if defined(_MSC_VER)
208  // CRT terminate() call handler
209  static void __cdecl TerminateHandler()
210  {
211  // Output error
212  GetInstance()._handler(__LOCATION__ + SystemException("Abnormal program termination (terminate() function was called)"), StackTrace(1));
213 
214  // Retrieve exception information
215  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
216  GetExceptionPointers(0, &pExceptionPtrs);
217 
218  // Write dump file
219  CreateDumpFile(pExceptionPtrs);
220 
221  // Delete exception information
222  DeleteExceptionPointers(pExceptionPtrs);
223 
224  // Terminate process
225  TerminateProcess(GetCurrentProcess(), 1);
226  }
227 
228  // CRT unexpected() call handler
229  static void __cdecl UnexpectedHandler()
230  {
231  // Output error
232  GetInstance()._handler(__LOCATION__ + SystemException("Unexpected error (unexpected() function was called)"), StackTrace(1));
233 
234  // Retrieve exception information
235  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
236  GetExceptionPointers(0, &pExceptionPtrs);
237 
238  // Write dump file
239  CreateDumpFile(pExceptionPtrs);
240 
241  // Delete exception information
242  DeleteExceptionPointers(pExceptionPtrs);
243 
244  // Terminate process
245  TerminateProcess(GetCurrentProcess(), 1);
246  }
247 #endif
248 
249  // CRT Pure virtual method call handler
250  static void __cdecl PureCallHandler()
251  {
252  // Output error
253  GetInstance()._handler(__LOCATION__ + SystemException("Pure virtual function call"), StackTrace(1));
254 
255  // Retrieve exception information
256  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
257  GetExceptionPointers(0, &pExceptionPtrs);
258 
259  // Write dump file
260  CreateDumpFile(pExceptionPtrs);
261 
262  // Delete exception information
263  DeleteExceptionPointers(pExceptionPtrs);
264 
265  // Terminate process
266  TerminateProcess(GetCurrentProcess(), 1);
267  }
268 
269  // CRT invalid parameter handler
270  static void __cdecl InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
271  {
272  // Output error
273  GetInstance()._handler(__LOCATION__ + SystemException("Invalid parameter exception"), StackTrace(1));
274 
275  // Retrieve exception information
276  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
277  GetExceptionPointers(0, &pExceptionPtrs);
278 
279  // Write dump file
280  CreateDumpFile(pExceptionPtrs);
281 
282  // Delete exception information
283  DeleteExceptionPointers(pExceptionPtrs);
284 
285  // Terminate process
286  TerminateProcess(GetCurrentProcess(), 1);
287  }
288 
289  // CRT new operator fault handler
290  static int __cdecl NewHandler(size_t)
291  {
292  // Output error
293  GetInstance()._handler(__LOCATION__ + SystemException("'new' operator memory allocation exception"), StackTrace(1));
294 
295  // Retrieve exception information
296  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
297  GetExceptionPointers(0, &pExceptionPtrs);
298 
299  // Write dump file
300  CreateDumpFile(pExceptionPtrs);
301 
302  // Delete exception information
303  DeleteExceptionPointers(pExceptionPtrs);
304 
305  // Terminate process
306  TerminateProcess(GetCurrentProcess(), 1);
307 
308  // Unreacheable code
309  return 0;
310  }
311 
312  // CRT SIGABRT signal handler
313  static void SigabrtHandler(int signum)
314  {
315  // Output error
316  GetInstance()._handler(__LOCATION__ + SystemException("Caught abort (SIGABRT) signal"), StackTrace(1));
317 
318  // Retrieve exception information
319  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
320  GetExceptionPointers(0, &pExceptionPtrs);
321 
322  // Write dump file
323  CreateDumpFile(pExceptionPtrs);
324 
325  // Delete exception information
326  DeleteExceptionPointers(pExceptionPtrs);
327 
328  // Terminate process
329  TerminateProcess(GetCurrentProcess(), 1);
330  }
331 
332  // CRT SIGFPE signal handler
333  static void SigfpeHandler(int signum, int subcode)
334  {
335  // Output error
336  GetInstance()._handler(__LOCATION__ + SystemException("Caught floating point exception (SIGFPE) signal"), StackTrace(1));
337 
338  // Retrieve exception information
339  EXCEPTION_POINTERS* pExceptionPtrs = (PEXCEPTION_POINTERS)_pxcptinfoptrs;
340 
341  // Write dump file
342  CreateDumpFile(pExceptionPtrs);
343 
344  // Terminate process
345  TerminateProcess(GetCurrentProcess(), 1);
346  }
347 
348  // CRT sigill signal handler
349  static void SigillHandler(int signum)
350  {
351  // Output error
352  GetInstance()._handler(__LOCATION__ + SystemException("Caught illegal instruction (SIGILL) signal"), StackTrace(1));
353 
354  // Retrieve exception information
355  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
356  GetExceptionPointers(0, &pExceptionPtrs);
357 
358  // Write dump file
359  CreateDumpFile(pExceptionPtrs);
360 
361  // Delete exception information
362  DeleteExceptionPointers(pExceptionPtrs);
363 
364  // Terminate process
365  TerminateProcess(GetCurrentProcess(), 1);
366  }
367 
368  // CRT sigint signal handler
369  static void SigintHandler(int signum)
370  {
371  // Output error
372  GetInstance()._handler(__LOCATION__ + SystemException("Caught interruption (SIGINT) signal"), StackTrace(1));
373 
374  // Retrieve exception information
375  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
376  GetExceptionPointers(0, &pExceptionPtrs);
377 
378  // Write dump file
379  CreateDumpFile(pExceptionPtrs);
380 
381  // Delete exception information
382  DeleteExceptionPointers(pExceptionPtrs);
383 
384  // Terminate process
385  TerminateProcess(GetCurrentProcess(), 1);
386  }
387 
388  // CRT SIGSEGV signal handler
389  static void SigsegvHandler(int signum)
390  {
391  // Output error
392  GetInstance()._handler(__LOCATION__ + SystemException("Caught invalid storage access (SIGSEGV) signal"), StackTrace(1));
393 
394  // Retrieve exception information
395  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
396  GetExceptionPointers(0, &pExceptionPtrs);
397 
398  // Write dump file
399  CreateDumpFile(pExceptionPtrs);
400 
401  // Terminate process
402  TerminateProcess(GetCurrentProcess(), 1);
403  }
404 
405  // CRT SIGTERM signal handler
406  static void SigtermHandler(int signum)
407  {
408  // Output error
409  GetInstance()._handler(__LOCATION__ + SystemException("Caught termination request (SIGTERM) signal"), StackTrace(1));
410 
411  // Retrieve exception information
412  EXCEPTION_POINTERS* pExceptionPtrs = nullptr;
413  GetExceptionPointers(0, &pExceptionPtrs);
414 
415  // Write dump file
416  CreateDumpFile(pExceptionPtrs);
417 
418  // Delete exception information
419  DeleteExceptionPointers(pExceptionPtrs);
420 
421  // Terminate process
422  TerminateProcess(GetCurrentProcess(), 1);
423  }
424 
425  static void GetExceptionPointers(DWORD dwExceptionCode, EXCEPTION_POINTERS** ppExceptionPointers)
426  {
427  CONTEXT ContextRecord;
428  memset(&ContextRecord, 0, sizeof(CONTEXT));
429 
430  EXCEPTION_RECORD ExceptionRecord;
431  memset(&ExceptionRecord, 0, sizeof(EXCEPTION_RECORD));
432 
433 #if defined(_M_IX86)
434  // On x86, we reserve some extra stack which won't be used. That is to
435  // preserve as much of the call frame as possible when the function with
436  // the buffer overrun entered __security_check_cookie with a JMP instead
437  // of a CALL, after the calling frame has been released in the epilogue
438  // of that function.
439  volatile ULONG dw[(sizeof(CONTEXT) + sizeof(EXCEPTION_RECORD)) / sizeof(ULONG)];
440 
441  // Save the state in the context record immediately. Hopefully, since
442  // opts are disabled, this will happen without modifying ECX, which has
443  // the local cookie which failed the check.
444  __asm
445  {
446  mov dword ptr [ContextRecord.Eax ], eax
447  mov dword ptr [ContextRecord.Ecx ], ecx
448  mov dword ptr [ContextRecord.Edx ], edx
449  mov dword ptr [ContextRecord.Ebx ], ebx
450  mov dword ptr [ContextRecord.Esi ], esi
451  mov dword ptr [ContextRecord.Edi ], edi
452  mov word ptr [ContextRecord.SegSs], ss
453  mov word ptr [ContextRecord.SegCs], cs
454  mov word ptr [ContextRecord.SegDs], ds
455  mov word ptr [ContextRecord.SegEs], es
456  mov word ptr [ContextRecord.SegFs], fs
457  mov word ptr [ContextRecord.SegGs], gs
458  pushfd
459  pop [ContextRecord.EFlags]
460 
461  // Set the context EBP/EIP/ESP to the values which would be found
462  // in the caller to __security_check_cookie.
463  mov eax, [ebp]
464  mov dword ptr [ContextRecord.Ebp], eax
465  mov eax, [ebp + 4]
466  mov dword ptr [ContextRecord.Eip], eax
467  lea eax, [ebp + 8]
468  mov dword ptr [ContextRecord.Esp], eax
469 
470  // Make sure the dummy stack space looks referenced.
471  mov eax, dword ptr dw
472  }
473 
474  ContextRecord.ContextFlags = CONTEXT_CONTROL;
475  ExceptionRecord.ExceptionAddress = (PVOID)(ULONG_PTR)ContextRecord.Eip;
476 #elif defined(_M_X64)
477  ULONG64 ControlPc;
478  ULONG64 EstablisherFrame;
479  ULONG64 ImageBase;
480  PRUNTIME_FUNCTION FunctionEntry;
481  PVOID HandlerData;
482 
483  RtlCaptureContext(&ContextRecord);
484 
485  ControlPc = ContextRecord.Rip;
486  FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, nullptr);
487 
488  if (FunctionEntry != nullptr)
489  RtlVirtualUnwind(UNW_FLAG_NHANDLER, ImageBase, ControlPc, FunctionEntry, &ContextRecord, &HandlerData, &EstablisherFrame, nullptr);
490 
491 #if defined(__GNUC__)
492  void* return_address = __builtin_return_address(0);
493  ContextRecord.Rip = (ULONGLONG)return_address;
494  ContextRecord.Rsp = (ULONGLONG)__builtin_extract_return_addr(return_address) + 8;
495 #elif defined(_MSC_VER)
496  ContextRecord.Rip = (ULONGLONG)_ReturnAddress();
497  ContextRecord.Rsp = (ULONGLONG)_AddressOfReturnAddress() + 8;
498 #endif
499  ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Rip;
500 #else
501  #error Unsupported architecture
502 #endif
503  ExceptionRecord.ExceptionCode = dwExceptionCode;
504 #if defined(__GNUC__)
505  ExceptionRecord.ExceptionAddress = __builtin_return_address(0);
506 #elif defined(_MSC_VER)
507  ExceptionRecord.ExceptionAddress = _ReturnAddress();
508 #endif
509 
510  CONTEXT* pContextRecord = new CONTEXT;
511  memcpy(pContextRecord, &ContextRecord, sizeof(CONTEXT));
512 
513  EXCEPTION_RECORD* pExceptionRecord = new EXCEPTION_RECORD;
514  memcpy(pExceptionRecord, &ExceptionRecord, sizeof(EXCEPTION_RECORD));
515 
516  *ppExceptionPointers = new EXCEPTION_POINTERS;
517  (*ppExceptionPointers)->ContextRecord = pContextRecord;
518  (*ppExceptionPointers)->ExceptionRecord = pExceptionRecord;
519  }
520 
521  static void DeleteExceptionPointers(EXCEPTION_POINTERS* pExceptionPointers)
522  {
523  delete pExceptionPointers->ContextRecord;
524  delete pExceptionPointers->ExceptionRecord;
525  delete pExceptionPointers;
526  }
527 
528  static void CreateDumpFile(EXCEPTION_POINTERS* pExcPtrs)
529  {
530 #if defined(DBGHELP_SUPPORT)
531  // Generate dump file name based on the current timestamp
532  Path dump = Path::executable().parent() / format("crash.{}.dmp", Timestamp::utc());
533 
534  // Create the dump file
535  HANDLE hDumpFile = CreateFileW(dump.wstring().c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
536  if (hDumpFile == INVALID_HANDLE_VALUE)
537  throwex FileSystemException("Cannot create a dump file!").Attach(dump);
538 
539  // Smart resource cleaner pattern
540  auto file = resource(hDumpFile, [](HANDLE hObject) { CloseHandle(hObject); });
541 
542  MINIDUMP_EXCEPTION_INFORMATION mei;
543  MINIDUMP_CALLBACK_INFORMATION mci;
544 
545  // Prepare dump file information
546  mei.ThreadId = GetCurrentThreadId();
547  mei.ExceptionPointers = pExcPtrs;
548  mei.ClientPointers = FALSE;
549  mci.CallbackRoutine = nullptr;
550  mci.CallbackParam = nullptr;
551 
552  // Write dump file information
553  if (!MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file.get(), MiniDumpNormal, &mei, nullptr, &mci))
554  throwex FileSystemException("Cannot write a dump file!").Attach(dump);
555 
556  // Release the resource manually
557  if (!CloseHandle(hDumpFile))
558  throwex FileSystemException("Cannot close a dump file!").Attach(dump);
559  file.release();
560 #endif
561  }
562 
563 #elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
564 
565  // Signal handler
566  static void SignalHandler(int signo, siginfo_t* info, void* context)
567  {
568  // Output error
569  switch (signo)
570  {
571  case SIGABRT:
572  GetInstance()._handler(__LOCATION__ + SystemException("Caught abnormal program termination (SIGABRT) signal"), StackTrace(1));
573  break;
574  case SIGALRM:
575  GetInstance()._handler(__LOCATION__ + SystemException("Caught alarm clock (SIGALRM) signal"), StackTrace(1));
576  break;
577  case SIGBUS:
578  GetInstance()._handler(__LOCATION__ + SystemException("Caught memory access error (SIGBUS) signal"), StackTrace(1));
579  break;
580  case SIGFPE:
581  GetInstance()._handler(__LOCATION__ + SystemException("Caught floating point exception (SIGFPE) signal"), StackTrace(1));
582  break;
583  case SIGHUP:
584  GetInstance()._handler(__LOCATION__ + SystemException("Caught hangup instruction (SIGHUP) signal"), StackTrace(1));
585  break;
586  case SIGILL:
587  GetInstance()._handler(__LOCATION__ + SystemException("Caught illegal instruction (SIGILL) signal"), StackTrace(1));
588  break;
589  case SIGINT:
590  GetInstance()._handler(__LOCATION__ + SystemException("Caught terminal interrupt (SIGINT) signal"), StackTrace(1));
591  break;
592  case SIGPIPE:
593  GetInstance()._handler(__LOCATION__ + SystemException("Caught pipe write error (SIGPIPE) signal"), StackTrace(1));
594  break;
595  case SIGPROF:
596  GetInstance()._handler(__LOCATION__ + SystemException("Caught profiling timer expired error (SIGPROF) signal"), StackTrace(1));
597  break;
598  case SIGQUIT:
599  GetInstance()._handler(__LOCATION__ + SystemException("Caught terminal quit (SIGQUIT) signal"), StackTrace(1));
600  break;
601  case SIGSEGV:
602  GetInstance()._handler(__LOCATION__ + SystemException("Caught illegal storage access error (SIGSEGV) signal"), StackTrace(1));
603  break;
604  case SIGSYS:
605  GetInstance()._handler(__LOCATION__ + SystemException("Caught bad system call (SIGSYS) signal"), StackTrace(1));
606  break;
607  case SIGTERM:
608  GetInstance()._handler(__LOCATION__ + SystemException("Caught termination request (SIGTERM) signal"), StackTrace(1));
609  break;
610  case SIGXCPU:
611  GetInstance()._handler(__LOCATION__ + SystemException("Caught CPU time limit exceeded (SIGXCPU) signal"), StackTrace(1));
612  break;
613  case SIGXFSZ:
614  GetInstance()._handler(__LOCATION__ + SystemException("Caught file size limit exceeded (SIGXFSZ) signal"), StackTrace(1));
615  break;
616  default:
617  GetInstance()._handler(__LOCATION__ + SystemException(format("Caught unknown signal - {}", signo)), StackTrace(1));
618  break;
619  }
620 
621  // Prepare signal action structure
622  struct sigaction sa;
623  memset(&sa, 0, sizeof(sa));
624  sa.sa_handler = SIG_DFL;
625 
626  // Setup the default signal handler and rise it!
627  int result = sigaction(signo, &sa, nullptr);
628  if (result == 0)
629  raise(signo);
630  else
631  kill(getpid(), SIGKILL);
632  }
633 
634 #endif
635 };
636 
638 
639 ExceptionsHandler::ExceptionsHandler()
640 {
641  // Check implementation storage parameters
642  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
643  static_assert((StorageSize >= sizeof(Impl)), "ExceptionsHandler::StorageSize must be increased!");
644  static_assert(((StorageAlign % alignof(Impl)) == 0), "ExceptionsHandler::StorageAlign must be adjusted!");
645 
646  // Create the implementation instance
647  new(&_storage)Impl();
648 }
649 
651 {
652  // Delete the implementation instance
653  reinterpret_cast<Impl*>(&_storage)->~Impl();
654 }
655 
656 void ExceptionsHandler::SetupHandler(const std::function<void (const SystemException&, const StackTrace&)>& handler) { GetInstance().impl().SetupHandler(handler); }
657 void ExceptionsHandler::SetupProcess() { GetInstance().impl().SetupProcess(); }
658 void ExceptionsHandler::SetupThread() { GetInstance().impl().SetupThread(); }
659 
660 } // namespace CppCommon
static void SetupProcess()
Setup exceptions handler for the current process.
static void SetupHandler(const std::function< void(const SystemException &, const StackTrace &)> &handler)
Setup new global exceptions handler function.
static void SetupThread()
Setup exceptions handler for the current thread.
Path parent() const
Decompose parent path from the current path.
Definition: path.cpp:144
static Path executable()
Get the executable path of the process.
Definition: path.cpp:910
static ExceptionsHandler & GetInstance()
Get singleton instance.
Definition: singleton.h:61
Stack trace snapshot provider.
Definition: stack_trace.h:33
System exception.
Definition: exceptions.h:107
static uint64_t utc()
Get the UTC timestamp.
Definition: timestamp.cpp:105
Static array countof definition.
#define throwex
Throw extended exception macro.
Definition: exceptions.h:23
Exceptions handler definition.
Format string definition.
C++ Common project definitions.
Definition: token_bucket.h:15
std::string format(fmt::format_string< T... > pattern, T &&... args)
Format string.
Definition: format.inl:12
auto resource(T handle, TCleaner cleaner)
Resource smart cleaner pattern.
Definition: resource.h:43
constexpr size_t countof(const T(&)[N]) noexcept
Count of elements in static array.
Definition: countof.h:16
Filesystem path definition.
Resource smart cleaner pattern definition.
#define __LOCATION__
Current source location macro.
Stack trace snapshot provider definition.
Timestamp definition.
Aligned storage validator definition.