1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // |
5 | |
6 | // |
7 | // EXCEPTMACROS.H - |
8 | // |
9 | // This header file exposes mechanisms to: |
10 | // |
11 | // 1. Throw COM+ exceptions using the COMPlusThrow() function |
12 | // 2. Guard a block of code using EX_TRY, and catch |
13 | // COM+ exceptions using EX_CATCH |
14 | // |
15 | // from the *unmanaged* portions of the EE. Much of the EE runs |
16 | // in a hybrid state where it runs like managed code but the code |
17 | // is produced by a classic unmanaged-code C++ compiler. |
18 | // |
19 | // THROWING A COM+ EXCEPTION |
20 | // ------------------------- |
21 | // To throw a COM+ exception, call the function: |
22 | // |
23 | // COMPlusThrow(OBJECTREF pThrowable); |
24 | // |
25 | // This function does not return. There are also various functions |
26 | // that wrap COMPlusThrow for convenience. |
27 | // |
28 | // COMPlusThrow() must only be called within the scope of a EX_TRY |
29 | // block. See below for more information. |
30 | // |
31 | // |
32 | // THROWING A RUNTIME EXCEPTION |
33 | // ---------------------------- |
34 | // COMPlusThrow() is overloaded to take a constant describing |
35 | // the common EE-generated exceptions, e.g. |
36 | // |
37 | // COMPlusThrow(kOutOfMemoryException); |
38 | // |
39 | // See rexcep.h for list of constants (prepend "k" to get the actual |
40 | // constant name.) |
41 | // |
42 | // You can also add a descriptive error string as follows: |
43 | // |
44 | // - Add a descriptive error string and resource id to |
45 | // COM99\src\dlls\mscorrc\resource.h and mscorrc.rc. |
46 | // Embed "%1", "%2" or "%3" to leave room for runtime string |
47 | // inserts. |
48 | // |
49 | // - Pass the resource ID and inserts to COMPlusThrow, i.e. |
50 | // |
51 | // COMPlusThrow(kSecurityException, |
52 | // IDS_CANTREFORMATCDRIVEBECAUSE, |
53 | // W("Formatting C drive permissions not granted.")); |
54 | // |
55 | // |
56 | // |
57 | // TO CATCH COMPLUS EXCEPTIONS: |
58 | // ---------------------------- |
59 | // |
60 | // Use the following syntax: |
61 | // |
62 | // #include "exceptmacros.h" |
63 | // |
64 | // |
65 | // OBJECTREF pThrownObject; |
66 | // |
67 | // EX_TRY { |
68 | // ...guarded code... |
69 | // } EX_CATCH { |
70 | // ...handler... |
71 | // } EX_END_CATCH(SwallowAllExceptions) |
72 | // |
73 | // |
74 | // EX_TRY blocks can be nested. |
75 | // |
76 | // From within the handler, you can call the GET_THROWABLE() macro to |
77 | // obtain the object that was thrown. |
78 | // |
79 | // CRUCIAL POINTS |
80 | // -------------- |
81 | // In order to call COMPlusThrow(), you *must* be within the scope |
82 | // of a EX_TRY block. Under _DEBUG, COMPlusThrow() will assert |
83 | // if you call it out of scope. This implies that just about every |
84 | // external entrypoint into the EE has to have a EX_TRY, in order |
85 | // to convert uncaught COM+ exceptions into some error mechanism |
86 | // more understandable to its non-COM+ caller. |
87 | // |
88 | // Any function that can throw a COM+ exception out to its caller |
89 | // has the same requirement. ALL such functions should be tagged |
90 | // with THROWS in CONTRACT. Aside from making the code |
91 | // self-document its contract, the checked version of this will fire |
92 | // an assert if the function is ever called without being in scope. |
93 | // |
94 | // |
95 | // AVOIDING EX_TRY GOTCHAS |
96 | // ---------------------------- |
97 | // EX_TRY/EX_CATCH actually expands into a Win32 SEH |
98 | // __try/__except structure. It does a lot of goo under the covers |
99 | // to deal with pre-emptive GC settings. |
100 | // |
101 | // 1. Do not use C++ or SEH try/__try use EX_TRY instead. |
102 | // |
103 | // 2. Remember that any function marked THROWS |
104 | // has the potential not to return. So be wary of allocating |
105 | // non-gc'd objects around such calls because ensuring cleanup |
106 | // of these things is not simple (you can wrap another EX_TRY |
107 | // around the call to simulate a COM+ "try-finally" but EX_TRY |
108 | // is relatively expensive compared to the real thing.) |
109 | // |
110 | // |
111 | |
112 | |
113 | #ifndef __exceptmacros_h__ |
114 | #define __exceptmacros_h__ |
115 | |
116 | struct _EXCEPTION_REGISTRATION_RECORD; |
117 | class Thread; |
118 | class Frame; |
119 | class Exception; |
120 | |
121 | VOID DECLSPEC_NORETURN RealCOMPlusThrowOM(); |
122 | VOID DECLSPEC_NORETURN RealCOMPlusThrowSO(); |
123 | |
124 | #include <excepcpu.h> |
125 | #include "stackprobe.h" |
126 | |
127 | |
128 | |
129 | //========================================================================== |
130 | // Macros to allow catching exceptions from within the EE. These are lightweight |
131 | // handlers that do not install the managed frame handler. |
132 | // |
133 | // struct Param { ... } param; |
134 | // EE_TRY_FOR_FINALLY(Param *, pParam, ¶m) { |
135 | // ...<guarded code>... |
136 | // } EE_FINALLY { |
137 | // ...<handler>... |
138 | // } EE_END_FINALLY |
139 | // |
140 | // EE_TRY(filter expr) { |
141 | // ...<guarded code>... |
142 | // } EE_CATCH { |
143 | // ...<handler>... |
144 | // } |
145 | //========================================================================== |
146 | |
147 | // __GotException will only be FALSE if got all the way through the code |
148 | // guarded by the try, otherwise it will be TRUE, so we know if we got into the |
149 | // finally from an exception or not. In which case need to reset the GC state back |
150 | // to what it was for the finally to run in that state. |
151 | |
152 | #define EE_TRY_FOR_FINALLY(ParamType, paramDef, paramRef) \ |
153 | { \ |
154 | struct __EEParam \ |
155 | { \ |
156 | BOOL fGCDisabled; \ |
157 | BOOL GotException; \ |
158 | ParamType param; \ |
159 | } __EEparam; \ |
160 | __EEparam.fGCDisabled = GetThread()->PreemptiveGCDisabled(); \ |
161 | __EEparam.GotException = TRUE; \ |
162 | __EEparam.param = paramRef; \ |
163 | PAL_TRY(__EEParam *, __pEEParam, &__EEparam) \ |
164 | { \ |
165 | ParamType paramDef; paramDef = __pEEParam->param; |
166 | |
167 | #define GOT_EXCEPTION() __EEparam.GotException |
168 | |
169 | #define EE_FINALLY \ |
170 | __pEEParam->GotException = FALSE; \ |
171 | } PAL_FINALLY { \ |
172 | if (__EEparam.GotException) { \ |
173 | if (__EEparam.fGCDisabled != GetThread()->PreemptiveGCDisabled()) { \ |
174 | if (__EEparam.fGCDisabled) \ |
175 | GetThread()->DisablePreemptiveGC(); \ |
176 | else \ |
177 | GetThread()->EnablePreemptiveGC(); \ |
178 | } \ |
179 | } |
180 | |
181 | #define EE_END_FINALLY \ |
182 | } \ |
183 | PAL_ENDTRY \ |
184 | } |
185 | |
186 | |
187 | |
188 | |
189 | //========================================================================== |
190 | // Helpful macros to declare exception handlers, their implementaiton, |
191 | // and to call them. |
192 | //========================================================================== |
193 | |
194 | #define _EXCEPTION_HANDLER_DECL(funcname) \ |
195 | EXCEPTION_DISPOSITION __cdecl funcname(EXCEPTION_RECORD *pExceptionRecord, \ |
196 | struct _EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, \ |
197 | CONTEXT *pContext, \ |
198 | DISPATCHER_CONTEXT *pDispatcherContext) |
199 | |
200 | #define EXCEPTION_HANDLER_DECL(funcname) \ |
201 | extern "C" _EXCEPTION_HANDLER_DECL(funcname) |
202 | |
203 | #define EXCEPTION_HANDLER_IMPL(funcname) \ |
204 | _EXCEPTION_HANDLER_DECL(funcname) |
205 | |
206 | #define EXCEPTION_HANDLER_FWD(funcname) \ |
207 | funcname(pExceptionRecord, pEstablisherFrame, pContext, pDispatcherContext) |
208 | |
209 | //========================================================================== |
210 | // Declares a COM+ frame handler that can be used to make sure that |
211 | // exceptions that should be handled from within managed code |
212 | // are handled within and don't leak out to give other handlers a |
213 | // chance at them. |
214 | //========================================================================== |
215 | #define INSTALL_COMPLUS_EXCEPTION_HANDLER() \ |
216 | DECLARE_CPFH_EH_RECORD(GET_THREAD()); \ |
217 | INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE() |
218 | |
219 | #define INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE() \ |
220 | { \ |
221 | INSTALL_EXCEPTION_HANDLING_RECORD(&(___pExRecord->m_ExReg)); \ |
222 | /* work around unreachable code warning */ \ |
223 | if (true) { |
224 | |
225 | #define UNINSTALL_COMPLUS_EXCEPTION_HANDLER() \ |
226 | } \ |
227 | UNINSTALL_EXCEPTION_HANDLING_RECORD(&(___pExRecord->m_ExReg)); \ |
228 | } |
229 | |
230 | #if !defined(WIN64EXCEPTIONS) |
231 | |
232 | #define INSTALL_NESTED_EXCEPTION_HANDLER(frame) \ |
233 | NestedHandlerExRecord *__pNestedHandlerExRecord = (NestedHandlerExRecord*) _alloca(sizeof(NestedHandlerExRecord)); \ |
234 | __pNestedHandlerExRecord->m_handlerInfo.m_hThrowable = NULL; \ |
235 | __pNestedHandlerExRecord->Init((PEXCEPTION_ROUTINE)COMPlusNestedExceptionHandler, frame); \ |
236 | INSTALL_EXCEPTION_HANDLING_RECORD(&(__pNestedHandlerExRecord->m_ExReg)); |
237 | |
238 | #define UNINSTALL_NESTED_EXCEPTION_HANDLER() \ |
239 | UNINSTALL_EXCEPTION_HANDLING_RECORD(&(__pNestedHandlerExRecord->m_ExReg)); |
240 | |
241 | #else // defined(WIN64EXCEPTIONS) |
242 | |
243 | #define INSTALL_NESTED_EXCEPTION_HANDLER(frame) |
244 | #define UNINSTALL_NESTED_EXCEPTION_HANDLER() |
245 | |
246 | #endif // !defined(WIN64EXCEPTIONS) |
247 | |
248 | LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo); |
249 | |
250 | // Actual UEF worker prototype for use by GCUnhandledExceptionFilter. |
251 | extern LONG InternalUnhandledExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo); |
252 | |
253 | //========================================================================== |
254 | // Installs a handler to unwind exception frames, but not catch the exception |
255 | //========================================================================== |
256 | |
257 | #ifdef FEATURE_CORRUPTING_EXCEPTIONS |
258 | // ----------------------------------------------------------------------- |
259 | // Support for Corrupted State Exceptions |
260 | // ----------------------------------------------------------------------- |
261 | // This enumeration defines the corruption severity of an exception and |
262 | // whether it should be reused for the next exception thrown or not. |
263 | enum CorruptionSeverity |
264 | { |
265 | UseLast = 0x0, // When specified, the last active corruption severity from TES should be used |
266 | NotSet = 0x1, // Corruption Severity has not been set - this is the default/reset value |
267 | NotCorrupting = 0x2, // Indicates exception is not corrupting |
268 | ProcessCorrupting = 0x4, // Indicates exception represents process corrupted state |
269 | ReuseForReraise = 0x2000 // Indicates that the corruption severity should be reused for the next exception thrown, |
270 | // provided its not nested and isnt a rethrow. This flag is used typically for propagation of |
271 | // severity across boundaries like Reflection invocation, AD transition etc. |
272 | }; |
273 | |
274 | #define GET_CORRUPTION_SEVERITY(severity) ((severity & (~ReuseForReraise))) |
275 | #define CAN_REUSE_CORRUPTION_SEVERITY(severity) ((severity & ReuseForReraise) == ReuseForReraise) |
276 | |
277 | #endif // FEATURE_CORRUPTING_EXCEPTIONS |
278 | |
279 | VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow |
280 | #ifdef FEATURE_CORRUPTING_EXCEPTIONS |
281 | , CorruptionSeverity severity |
282 | #endif // FEATURE_CORRUPTING_EXCEPTIONS |
283 | ); |
284 | |
285 | VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL rethrow, BOOL fForStackOverflow = FALSE); |
286 | |
287 | #if defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE) |
288 | |
289 | #define INSTALL_UNWIND_AND_CONTINUE_HANDLER |
290 | #define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER |
291 | |
292 | #define INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE |
293 | #define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE |
294 | #else // DACCESS_COMPILE || CROSSGEN_COMPILE |
295 | |
296 | void UnwindAndContinueRethrowHelperInsideCatch(Frame* pEntryFrame, Exception* pException); |
297 | VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFrame, Exception* pException); |
298 | |
299 | #ifdef FEATURE_PAL |
300 | VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHardwareException); |
301 | |
302 | #define INSTALL_MANAGED_EXCEPTION_DISPATCHER \ |
303 | PAL_SEHException exCopy; \ |
304 | bool hasCaughtException = false; \ |
305 | try { |
306 | |
307 | #define UNINSTALL_MANAGED_EXCEPTION_DISPATCHER \ |
308 | } \ |
309 | catch (PAL_SEHException& ex) \ |
310 | { \ |
311 | exCopy = std::move(ex); \ |
312 | hasCaughtException = true; \ |
313 | } \ |
314 | if (hasCaughtException) \ |
315 | { \ |
316 | DispatchManagedException(exCopy, false);\ |
317 | } |
318 | |
319 | // Install trap that catches unhandled managed exception and dumps its stack |
320 | #define INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP \ |
321 | try { |
322 | |
323 | // Uninstall trap that catches unhandled managed exception and dumps its stack |
324 | #define UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP \ |
325 | } \ |
326 | catch (PAL_SEHException& ex) \ |
327 | { \ |
328 | if (!GetThread()->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException)) \ |
329 | { \ |
330 | LONG disposition = InternalUnhandledExceptionFilter_Worker(&ex.ExceptionPointers); \ |
331 | _ASSERTE(disposition == EXCEPTION_CONTINUE_SEARCH); \ |
332 | } \ |
333 | TerminateProcess(GetCurrentProcess(), 1); \ |
334 | UNREACHABLE(); \ |
335 | } |
336 | |
337 | #else // FEATURE_PAL |
338 | |
339 | #define INSTALL_MANAGED_EXCEPTION_DISPATCHER |
340 | #define UNINSTALL_MANAGED_EXCEPTION_DISPATCHER |
341 | #define INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP |
342 | #define UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP |
343 | |
344 | #endif // FEATURE_PAL |
345 | |
346 | #define INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE \ |
347 | { \ |
348 | MAKE_CURRENT_THREAD_AVAILABLE(); \ |
349 | Exception* __pUnCException = NULL; \ |
350 | Frame* __pUnCEntryFrame = CURRENT_THREAD->GetFrame(); \ |
351 | bool __fExceptionCatched = false; \ |
352 | SCAN_EHMARKER(); \ |
353 | if (true) PAL_CPP_TRY { \ |
354 | SCAN_EHMARKER_TRY(); \ |
355 | DEBUG_ASSURE_NO_RETURN_BEGIN(IUACH) |
356 | |
357 | #define INSTALL_UNWIND_AND_CONTINUE_HANDLER \ |
358 | INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE \ |
359 | /* The purpose of the INSTALL_UNWIND_AND_CONTINUE_HANDLER is to translate an exception to a managed */ \ |
360 | /* exception before it hits managed code. The transition to SO_INTOLERANT code does not logically belong here. */ \ |
361 | /* However, we don't want to miss any probe points and the intersection between a probe point and installing */ \ |
362 | /* an INSTALL_UNWIND_AND_CONTINUE_HANDLER is very high. The probes are very cheap, so we can tolerate */ \ |
363 | /* those few places where we are probing and don't need to. */ \ |
364 | /* Ideally, we would instead have an encompassing ENTER_SO_INTOLERANT_CODE macro that would */ \ |
365 | /* include INSTALL_UNWIND_AND_CONTINUE_HANDLER */ \ |
366 | BEGIN_SO_INTOLERANT_CODE(GET_THREAD()); |
367 | |
368 | // Optimized version for helper method frame. Avoids redundant GetThread() calls. |
369 | #define INSTALL_UNWIND_AND_CONTINUE_HANDLER_FOR_HMF(pHelperFrame) \ |
370 | { \ |
371 | Exception* __pUnCException = NULL; \ |
372 | Frame* __pUnCEntryFrame = (pHelperFrame); \ |
373 | bool __fExceptionCatched = false; \ |
374 | SCAN_EHMARKER(); \ |
375 | if (true) PAL_CPP_TRY { \ |
376 | SCAN_EHMARKER_TRY(); \ |
377 | DEBUG_ASSURE_NO_RETURN_BEGIN(IUACH); \ |
378 | BEGIN_SO_INTOLERANT_CODE(GET_THREAD()); |
379 | |
380 | #define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE \ |
381 | DEBUG_ASSURE_NO_RETURN_END(IUACH) \ |
382 | SCAN_EHMARKER_END_TRY(); \ |
383 | } \ |
384 | PAL_CPP_CATCH_DERIVED (Exception, __pException) \ |
385 | { \ |
386 | SCAN_EHMARKER_CATCH(); \ |
387 | CONSISTENCY_CHECK(NULL != __pException); \ |
388 | __pUnCException = __pException; \ |
389 | UnwindAndContinueRethrowHelperInsideCatch(__pUnCEntryFrame, __pUnCException); \ |
390 | __fExceptionCatched = true; \ |
391 | SCAN_EHMARKER_END_CATCH(); \ |
392 | } \ |
393 | PAL_CPP_ENDTRY \ |
394 | if (__fExceptionCatched) \ |
395 | { \ |
396 | SCAN_EHMARKER_CATCH(); \ |
397 | UnwindAndContinueRethrowHelperAfterCatch(__pUnCEntryFrame, __pUnCException); \ |
398 | } \ |
399 | } \ |
400 | |
401 | #define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER \ |
402 | END_SO_INTOLERANT_CODE; \ |
403 | UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE; \ |
404 | |
405 | #endif // DACCESS_COMPILE || CROSSGEN_COMPILE |
406 | |
407 | |
408 | #define ENCLOSE_IN_EXCEPTION_HANDLER( func ) \ |
409 | { \ |
410 | struct exception_handler_wrapper \ |
411 | { \ |
412 | static void wrap() \ |
413 | { \ |
414 | INSTALL_UNWIND_AND_CONTINUE_HANDLER; \ |
415 | func(); \ |
416 | UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; \ |
417 | } \ |
418 | }; \ |
419 | \ |
420 | exception_handler_wrapper::wrap(); \ |
421 | } |
422 | |
423 | |
424 | //========================================================================== |
425 | // Declares that a function can throw a COM+ exception. |
426 | //========================================================================== |
427 | #if defined(ENABLE_CONTRACTS) && !defined(DACCESS_COMPILE) |
428 | |
429 | //========================================================================== |
430 | // Declares that a function cannot throw a COM+ exception. |
431 | // Adds a record to the contract chain. |
432 | //========================================================================== |
433 | |
434 | #define CANNOTTHROWCOMPLUSEXCEPTION() ANNOTATION_NOTHROW; \ |
435 | COMPlusCannotThrowExceptionHelper _dummyvariable(TRUE, __FUNCTION__, __FILE__, __LINE__); |
436 | |
437 | extern const char *g_ExceptionFile; |
438 | extern DWORD g_ExceptionLine; |
439 | |
440 | #define THROWLOG() ( g_ExceptionFile = __FILE__, g_ExceptionLine = __LINE__, TRUE ) |
441 | |
442 | #define COMPlusThrow if(THROWLOG() && 0) { } else RealCOMPlusThrow |
443 | #define COMPlusThrowNonLocalized if(THROWLOG() && 0) { } else RealCOMPlusThrowNonLocalized |
444 | #define COMPlusThrowHR if(THROWLOG() && 0) { } else RealCOMPlusThrowHR |
445 | #define COMPlusThrowWin32 if(THROWLOG() && 0) { } else RealCOMPlusThrowWin32 |
446 | #define COMPlusThrowOM if(THROWLOG() && 0) { } else RealCOMPlusThrowOM |
447 | #ifdef FEATURE_STACK_PROBE |
448 | #define COMPlusThrowSO if(THROWLOG() && 0) { } else RealCOMPlusThrowSO |
449 | #endif |
450 | #define COMPlusThrowArithmetic if(THROWLOG() && 0) { } else RealCOMPlusThrowArithmetic |
451 | #define COMPlusThrowArgumentNull if(THROWLOG() && 0) { } else RealCOMPlusThrowArgumentNull |
452 | #define COMPlusThrowArgumentOutOfRange if(THROWLOG() && 0) { } else RealCOMPlusThrowArgumentOutOfRange |
453 | #define COMPlusThrowArgumentException if(THROWLOG() && 0) { } else RealCOMPlusThrowArgumentException |
454 | #define COMPlusThrowInvalidCastException if(THROWLOG() && 0) { } else RealCOMPlusThrowInvalidCastException |
455 | #define COMPlusRareRethrow if(THROWLOG() && 0) { } else RealCOMPlusRareRethrow |
456 | |
457 | #else // ENABLE_CONTRACTS && !DACCESS_COMPILE |
458 | |
459 | #define CANNOTTHROWCOMPLUSEXCEPTION() ANNOTATION_NOTHROW |
460 | #define BEGINCANNOTTHROWCOMPLUSEXCEPTION_SEH() ANNOTATION_NOTHROW |
461 | #define ENDCANNOTTHROWCOMPLUSEXCEPTION_SEH() |
462 | |
463 | #define COMPlusThrow RealCOMPlusThrow |
464 | #define COMPlusThrowNonLocalized RealCOMPlusThrowNonLocalized |
465 | #ifndef DACCESS_COMPILE |
466 | #define COMPlusThrowHR RealCOMPlusThrowHR |
467 | #else |
468 | #define COMPlusThrowHR ThrowHR |
469 | #endif |
470 | #define COMPlusThrowWin32 RealCOMPlusThrowWin32 |
471 | #define COMPlusThrowOM RealCOMPlusThrowOM |
472 | #ifdef FEATURE_STACK_PROBE |
473 | #define COMPlusThrowSO RealCOMPlusThrowSO |
474 | #endif |
475 | #define COMPlusThrowArithmetic RealCOMPlusThrowArithmetic |
476 | #define COMPlusThrowArgumentNull RealCOMPlusThrowArgumentNull |
477 | #define COMPlusThrowArgumentOutOfRange RealCOMPlusThrowArgumentOutOfRange |
478 | #define COMPlusThrowArgumentException RealCOMPlusThrowArgumentException |
479 | #define COMPlusThrowInvalidCastException RealCOMPlusThrowInvalidCastException |
480 | |
481 | #endif // ENABLE_CONTRACTS && !DACCESS_COMPILE |
482 | /* Non-VM exception helpers to be rerouted inside the VM directory: |
483 | ThrowHR |
484 | ThrowWin32 |
485 | ThrowLastError -->ThrowWin32(GetLastError()) |
486 | ThrowOutOfMemory COMPlusThrowOM defers to this |
487 | ThrowStackOverflow COMPlusThrowSO defers to this |
488 | ThrowMessage ThrowHR(E_FAIL, Message) |
489 | |
490 | */ |
491 | |
492 | /* Ideally we could make these defines. But the sources in the VM directory |
493 | won't build with them as defines. @todo: go through VM directory and |
494 | eliminate calls to the non-VM style functions. |
495 | |
496 | #define ThrowHR COMPlusThrowHR |
497 | #define ThrowWin32 COMPlusThrowWin32 |
498 | #define ThrowLastError() COMPlusThrowWin32(GetLastError()) |
499 | #define ThrowMessage "Don't use this in the VM directory" |
500 | |
501 | */ |
502 | |
503 | //====================================================== |
504 | // Used when we're entering the EE from unmanaged code |
505 | // and we can assert that the gc state is cooperative. |
506 | // |
507 | // If an exception is thrown through this transition |
508 | // handler, it will clean up the EE appropriately. See |
509 | // the definition of COMPlusCooperativeTransitionHandler |
510 | // for the details. |
511 | //====================================================== |
512 | |
513 | void COMPlusCooperativeTransitionHandler(Frame* pFrame); |
514 | |
515 | #ifdef CROSSGEN_COMPILE |
516 | |
517 | #define COOPERATIVE_TRANSITION_BEGIN() |
518 | #define COOPERATIVE_TRANSITION_END() |
519 | |
520 | #else // CROSSGEN_COMPILE |
521 | |
522 | #define COOPERATIVE_TRANSITION_BEGIN() \ |
523 | { \ |
524 | MAKE_CURRENT_THREAD_AVAILABLE(); \ |
525 | BEGIN_GCX_ASSERT_PREEMP; \ |
526 | BEGIN_SO_INTOLERANT_CODE(CURRENT_THREAD); \ |
527 | CoopTransitionHolder __CoopTransition(CURRENT_THREAD); \ |
528 | DEBUG_ASSURE_NO_RETURN_BEGIN(COOP_TRANSITION) |
529 | |
530 | #define COOPERATIVE_TRANSITION_END() \ |
531 | DEBUG_ASSURE_NO_RETURN_END(COOP_TRANSITION) \ |
532 | __CoopTransition.SuppressRelease(); \ |
533 | END_SO_INTOLERANT_CODE; \ |
534 | END_GCX_ASSERT_PREEMP; \ |
535 | } |
536 | |
537 | #endif // CROSSGEN_COMPILE |
538 | |
539 | extern LONG UserBreakpointFilter(EXCEPTION_POINTERS *ep); |
540 | extern LONG DefaultCatchFilter(EXCEPTION_POINTERS *ep, LPVOID pv); |
541 | extern LONG DefaultCatchNoSwallowFilter(EXCEPTION_POINTERS *ep, LPVOID pv); |
542 | |
543 | |
544 | // the only valid parameter for DefaultCatchFilter |
545 | #define COMPLUS_EXCEPTION_EXECUTE_HANDLER (PVOID)EXCEPTION_EXECUTE_HANDLER |
546 | struct DefaultCatchFilterParam |
547 | { |
548 | PVOID pv; // must be COMPLUS_EXCEPTION_EXECUTE_HANDLER |
549 | DefaultCatchFilterParam() {} |
550 | DefaultCatchFilterParam(PVOID _pv) : pv(_pv) {} |
551 | }; |
552 | |
553 | template <typename T> |
554 | LPCWSTR GetPathForErrorMessagesT(T *pImgObj) |
555 | { |
556 | SUPPORTS_DAC_HOST_ONLY; |
557 | if (pImgObj) |
558 | { |
559 | return pImgObj->GetPathForErrorMessages(); |
560 | } |
561 | else |
562 | { |
563 | return W("" ); |
564 | } |
565 | } |
566 | |
567 | VOID ThrowBadFormatWorker(UINT resID, LPCWSTR imageName DEBUGARG(__in_z const char *cond)); |
568 | |
569 | template <typename T> |
570 | NOINLINE |
571 | VOID ThrowBadFormatWorkerT(UINT resID, T * pImgObj DEBUGARG(__in_z const char *cond)) |
572 | { |
573 | LPCWSTR tmpStr = GetPathForErrorMessagesT(pImgObj); |
574 | ThrowBadFormatWorker(resID, tmpStr DEBUGARG(cond)); |
575 | } |
576 | |
577 | |
578 | // Worker macro for throwing BadImageFormat exceptions. |
579 | // |
580 | // resID: resource ID in mscorrc.rc. Message may not have substitutions. resID is permitted (but not encouraged) to be 0. |
581 | // imgObj: one of Module* or PEFile* or PEImage* (must support GetPathForErrorMessages method.) |
582 | // |
583 | #define IfFailThrowBF(hresult, resID, imgObj) \ |
584 | do \ |
585 | { \ |
586 | if (FAILED(hresult)) \ |
587 | THROW_BAD_FORMAT(resID, imgObj); \ |
588 | } \ |
589 | while(0) |
590 | |
591 | |
592 | #define THROW_BAD_FORMAT(resID, imgObj) THROW_BAD_FORMAT_MAYBE(FALSE, resID, imgObj) |
593 | |
594 | |
595 | // Conditional version of THROW_BAD_FORMAT. Do not use for new callsites. This is really meant to be a drop-in replacement |
596 | // for the obsolete BAD_FORMAT_ASSERT. |
597 | |
598 | #define THROW_BAD_FORMAT_MAYBE(cond, resID, imgObj) \ |
599 | do \ |
600 | { \ |
601 | if (!(cond)) \ |
602 | { \ |
603 | ThrowBadFormatWorkerT((resID), (imgObj) DEBUGARG(#cond)); \ |
604 | } \ |
605 | } \ |
606 | while(0) |
607 | |
608 | |
609 | // Same as above, but allows you to specify your own HRESULT |
610 | #define THROW_HR_ERROR_WITH_INFO(hr, imgObj) RealCOMPlusThrowHR(hr, hr, GetPathForErrorMessagesT(imgObj)) |
611 | |
612 | |
613 | #endif // __exceptmacros_h__ |
614 | |