Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
catch_fatal_condition.cpp
Go to the documentation of this file.
1/*
2 * Created by Phil on 21/08/2014
3 * Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
4 *
5 * Distributed under the Boost Software License, Version 1.0. (See accompanying
6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 *
8 */
9
11
12#include "catch_context.h"
14
15#if defined(__GNUC__)
16# pragma GCC diagnostic push
17# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
18#endif
19
20#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
21
22namespace {
23 // Report the error condition
24 void reportFatal( char const * const message ) {
26 }
27}
28
29#endif // signals/SEH handling
30
31#if defined( CATCH_CONFIG_WINDOWS_SEH )
32
33namespace Catch {
34 struct SignalDefs { DWORD id; const char* name; };
35
36 // There is no 1-1 mapping between signals and windows exceptions.
37 // Windows can easily distinguish between SO and SigSegV,
38 // but SigInt, SigTerm, etc are handled differently.
39 static SignalDefs signalDefs[] = {
40 { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" },
41 { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" },
42 { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" },
43 { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
44 };
45
46 LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
47 for (auto const& def : signalDefs) {
48 if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
49 reportFatal(def.name);
50 }
51 }
52 // If its not an exception we care about, pass it along.
53 // This stops us from eating debugger breaks etc.
54 return EXCEPTION_CONTINUE_SEARCH;
55 }
56
58 isSet = true;
59 // 32k seems enough for Catch to handle stack overflow,
60 // but the value was found experimentally, so there is no strong guarantee
61 guaranteeSize = 32 * 1024;
62 exceptionHandlerHandle = nullptr;
63 // Register as first handler in current chain
64 exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
65 // Pass in guarantee size to be filled
66 SetThreadStackGuarantee(&guaranteeSize);
67 }
68
70 if (isSet) {
71 RemoveVectoredExceptionHandler(exceptionHandlerHandle);
72 SetThreadStackGuarantee(&guaranteeSize);
73 exceptionHandlerHandle = nullptr;
74 isSet = false;
75 }
76 }
77
79 reset();
80 }
81
83ULONG FatalConditionHandler::guaranteeSize = 0;
84PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
85
86
87} // namespace Catch
88
89#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
90
91namespace Catch {
92
93 struct SignalDefs {
94 int id;
95 const char* name;
96 };
97
98 // 32kb for the alternate stack seems to be sufficient. However, this value
99 // is experimentally determined, so that's not guaranteed.
100 constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
101
102 static SignalDefs signalDefs[] = {
103 { SIGINT, "SIGINT - Terminal interrupt signal" },
104 { SIGILL, "SIGILL - Illegal instruction signal" },
105 { SIGFPE, "SIGFPE - Floating point error signal" },
106 { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
107 { SIGTERM, "SIGTERM - Termination request signal" },
108 { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
109 };
110
111
113 char const * name = "<unknown signal>";
114 for (auto const& def : signalDefs) {
115 if (sig == def.id) {
116 name = def.name;
117 break;
118 }
119 }
120 reset();
121 reportFatal(name);
122 raise( sig );
123 }
124
126 isSet = true;
127 stack_t sigStack;
128 sigStack.ss_sp = altStackMem;
129 sigStack.ss_size = sigStackSize;
130 sigStack.ss_flags = 0;
131 sigaltstack(&sigStack, &oldSigStack);
132 struct sigaction sa = { };
133
134 sa.sa_handler = handleSignal;
135 sa.sa_flags = SA_ONSTACK;
136 for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
137 sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
138 }
139 }
140
141
145
147 if( isSet ) {
148 // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
149 for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
150 sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
151 }
152 // Return the old stack
153 sigaltstack(&oldSigStack, nullptr);
154 isSet = false;
155 }
156 }
157
158 bool FatalConditionHandler::isSet = false;
159 struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
161 char FatalConditionHandler::altStackMem[sigStackSize] = {};
162
163
164} // namespace Catch
165
166#else
167
168namespace Catch {
170}
171
172#endif // signals/SEH handling
173
174#if defined(__GNUC__)
175# pragma GCC diagnostic pop
176#endif
std::string name
IContext & getCurrentContext()
static struct sigaction oldSigActions[]
virtual IResultCapture * getResultCapture()=0
virtual void handleFatalErrorCondition(StringRef message)=0
c_gkp_out sizeof(template))