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
116struct _EXCEPTION_REGISTRATION_RECORD;
117class Thread;
118class Frame;
119class Exception;
120
121VOID DECLSPEC_NORETURN RealCOMPlusThrowOM();
122VOID 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, &param) {
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
248LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo);
249
250// Actual UEF worker prototype for use by GCUnhandledExceptionFilter.
251extern 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.
263enum 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
279VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow
280#ifdef FEATURE_CORRUPTING_EXCEPTIONS
281 , CorruptionSeverity severity
282#endif // FEATURE_CORRUPTING_EXCEPTIONS
283);
284
285VOID 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
296void UnwindAndContinueRethrowHelperInsideCatch(Frame* pEntryFrame, Exception* pException);
297VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFrame, Exception* pException);
298
299#ifdef FEATURE_PAL
300VOID 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
437extern const char *g_ExceptionFile;
438extern 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:
483ThrowHR
484ThrowWin32
485ThrowLastError -->ThrowWin32(GetLastError())
486ThrowOutOfMemory COMPlusThrowOM defers to this
487ThrowStackOverflow COMPlusThrowSO defers to this
488ThrowMessage 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
513void 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
539extern LONG UserBreakpointFilter(EXCEPTION_POINTERS *ep);
540extern LONG DefaultCatchFilter(EXCEPTION_POINTERS *ep, LPVOID pv);
541extern 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
546struct DefaultCatchFilterParam
547{
548 PVOID pv; // must be COMPLUS_EXCEPTION_EXECUTE_HANDLER
549 DefaultCatchFilterParam() {}
550 DefaultCatchFilterParam(PVOID _pv) : pv(_pv) {}
551};
552
553template <typename T>
554LPCWSTR 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
567VOID ThrowBadFormatWorker(UINT resID, LPCWSTR imageName DEBUGARG(__in_z const char *cond));
568
569template <typename T>
570NOINLINE
571VOID 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