@@ -78,6 +78,9 @@ static bool gCrashRecoveryEnabled = false;
78
78
static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
79
79
tlIsRecoveringFromCrash;
80
80
81
+ static void installExceptionOrSignalHandlers ();
82
+ static void uninstallExceptionOrSignalHandlers ();
83
+
81
84
CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup () {}
82
85
83
86
CrashRecoveryContext::~CrashRecoveryContext () {
@@ -113,6 +116,23 @@ CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
113
116
return CRCI->CRC ;
114
117
}
115
118
119
+ void CrashRecoveryContext::Enable () {
120
+ sys::ScopedLock L (*gCrashRecoveryContextMutex );
121
+ // FIXME: Shouldn't this be a refcount or something?
122
+ if (gCrashRecoveryEnabled )
123
+ return ;
124
+ gCrashRecoveryEnabled = true ;
125
+ installExceptionOrSignalHandlers ();
126
+ }
127
+
128
+ void CrashRecoveryContext::Disable () {
129
+ sys::ScopedLock L (*gCrashRecoveryContextMutex );
130
+ if (!gCrashRecoveryEnabled )
131
+ return ;
132
+ gCrashRecoveryEnabled = false ;
133
+ uninstallExceptionOrSignalHandlers ();
134
+ }
135
+
116
136
void CrashRecoveryContext::registerCleanup (CrashRecoveryContextCleanup *cleanup)
117
137
{
118
138
if (!cleanup)
@@ -140,27 +160,56 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
140
160
delete cleanup;
141
161
}
142
162
143
- #ifdef LLVM_ON_WIN32
163
+ #if defined(_MSC_VER)
164
+ // If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way
165
+ // better than VEH. Vectored exception handling catches all exceptions happening
166
+ // on the thread with installed exception handlers, so it can interfere with
167
+ // internal exception handling of other libraries on that thread. SEH works
168
+ // exactly as you would expect normal exception handling to work: it only
169
+ // catches exceptions if they would bubble out from the stack frame with __try /
170
+ // __except.
144
171
145
- #include " Windows/WindowsSupport.h"
172
+ static void installExceptionOrSignalHandlers () {}
173
+ static void uninstallExceptionOrSignalHandlers () {}
146
174
147
- // On Windows, we can make use of vectored exception handling to
148
- // catch most crashing situations. Note that this does mean
149
- // we will be alerted of exceptions *before* structured exception
150
- // handling has the opportunity to catch it. But that isn't likely
151
- // to cause problems because nowhere in the project is SEH being
152
- // used.
175
+ bool CrashRecoveryContext::RunSafely (function_ref<void ()> Fn) {
176
+ if (!gCrashRecoveryEnabled ) {
177
+ Fn ();
178
+ return true ;
179
+ }
180
+
181
+ bool Result = true ;
182
+ __try {
183
+ Fn ();
184
+ } __except (1 ) { // Catch any exception.
185
+ Result = false ;
186
+ }
187
+ return Result;
188
+ }
189
+
190
+ #else // !_MSC_VER
191
+
192
+ #if defined(LLVM_ON_WIN32)
193
+ // This is a non-MSVC compiler, probably mingw gcc or clang without
194
+ // -fms-extensions. Use vectored exception handling (VEH).
195
+ //
196
+ // On Windows, we can make use of vectored exception handling to catch most
197
+ // crashing situations. Note that this does mean we will be alerted of
198
+ // exceptions *before* structured exception handling has the opportunity to
199
+ // catch it. Unfortunately, this causes problems in practice with other code
200
+ // running on threads with LLVM crash recovery contexts, so we would like to
201
+ // eventually move away from VEH.
153
202
//
154
- // Vectored exception handling is built on top of SEH, and so it
155
- // works on a per-thread basis.
203
+ // Vectored works on a per-thread basis, which is an advantage over
204
+ // SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have
205
+ // any native support for chaining exception handlers, but VEH allows more than
206
+ // one.
156
207
//
157
208
// The vectored exception handler functionality was added in Windows
158
209
// XP, so if support for older versions of Windows is required,
159
210
// it will have to be added.
160
- //
161
- // If we want to support as far back as Win2k, we could use the
162
- // SetUnhandledExceptionFilter API, but there's a risk of that
163
- // being entirely overwritten (it's not a chain).
211
+
212
+ #include " Windows/WindowsSupport.h"
164
213
165
214
static LONG CALLBACK ExceptionHandler (PEXCEPTION_POINTERS ExceptionInfo)
166
215
{
@@ -203,14 +252,7 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
203
252
// non-NULL, valid VEH handles, or NULL.
204
253
static sys::ThreadLocal<const void > sCurrentExceptionHandle ;
205
254
206
- void CrashRecoveryContext::Enable () {
207
- sys::ScopedLock L (*gCrashRecoveryContextMutex );
208
-
209
- if (gCrashRecoveryEnabled )
210
- return ;
211
-
212
- gCrashRecoveryEnabled = true ;
213
-
255
+ static void installExceptionOrSignalHandlers () {
214
256
// We can set up vectored exception handling now. We will install our
215
257
// handler as the front of the list, though there's no assurances that
216
258
// it will remain at the front (another call could install itself before
@@ -219,14 +261,7 @@ void CrashRecoveryContext::Enable() {
219
261
sCurrentExceptionHandle .set (handle);
220
262
}
221
263
222
- void CrashRecoveryContext::Disable () {
223
- sys::ScopedLock L (*gCrashRecoveryContextMutex );
224
-
225
- if (!gCrashRecoveryEnabled )
226
- return ;
227
-
228
- gCrashRecoveryEnabled = false ;
229
-
264
+ static void uninstallExceptionOrSignalHandlers () {
230
265
PVOID currentHandle = const_cast <PVOID>(sCurrentExceptionHandle .get ());
231
266
if (currentHandle) {
232
267
// Now we can remove the vectored exception handler from the chain
@@ -237,7 +272,7 @@ void CrashRecoveryContext::Disable() {
237
272
}
238
273
}
239
274
240
- #else
275
+ #else // !LLVM_ON_WIN32
241
276
242
277
// Generic POSIX implementation.
243
278
//
@@ -289,14 +324,7 @@ static void CrashRecoverySignalHandler(int Signal) {
289
324
const_cast <CrashRecoveryContextImpl*>(CRCI)->HandleCrash ();
290
325
}
291
326
292
- void CrashRecoveryContext::Enable () {
293
- sys::ScopedLock L (*gCrashRecoveryContextMutex );
294
-
295
- if (gCrashRecoveryEnabled )
296
- return ;
297
-
298
- gCrashRecoveryEnabled = true ;
299
-
327
+ static void installExceptionOrSignalHandlers () {
300
328
// Setup the signal handler.
301
329
struct sigaction Handler;
302
330
Handler.sa_handler = CrashRecoverySignalHandler;
@@ -308,20 +336,13 @@ void CrashRecoveryContext::Enable() {
308
336
}
309
337
}
310
338
311
- void CrashRecoveryContext::Disable () {
312
- sys::ScopedLock L (*gCrashRecoveryContextMutex );
313
-
314
- if (!gCrashRecoveryEnabled )
315
- return ;
316
-
317
- gCrashRecoveryEnabled = false ;
318
-
339
+ static void uninstallExceptionOrSignalHandlers () {
319
340
// Restore the previous signal handlers.
320
341
for (unsigned i = 0 ; i != NumSignals; ++i)
321
342
sigaction (Signals[i], &PrevActions[i], nullptr );
322
343
}
323
344
324
- #endif
345
+ #endif // !LLVM_ON_WIN32
325
346
326
347
bool CrashRecoveryContext::RunSafely (function_ref<void ()> Fn) {
327
348
// If crash recovery is disabled, do nothing.
@@ -339,6 +360,8 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
339
360
return true ;
340
361
}
341
362
363
+ #endif // !_MSC_VER
364
+
342
365
void CrashRecoveryContext::HandleCrash () {
343
366
CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
344
367
assert (CRCI && " Crash recovery context never initialized!" );
0 commit comments