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#if !defined(_EX_H_)
7#define _EX_H_
8
9#ifdef FEATURE_PAL
10#define EX_TRY_HOLDER \
11 HardwareExceptionHolder \
12 NativeExceptionHolderCatchAll __exceptionHolder; \
13 __exceptionHolder.Push(); \
14
15#else // FEATURE_PAL
16#define EX_TRY_HOLDER
17#endif // FEATURE_PAL
18
19#include "sstring.h"
20#include "crtwrap.h"
21#include "winwrap.h"
22#include "corerror.h"
23#include "stresslog.h"
24#include "genericstackprobe.h"
25#include "staticcontract.h"
26#include "entrypoints.h"
27
28#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
29#define _DEBUG_IMPL 1
30#endif
31
32
33//===========================================================================================
34// These abstractions hide the difference between legacy desktop CLR's (that don't support
35// side-by-side-inproc and rely on a fixed SEH code to identify managed exceptions) and
36// new CLR's that support side-by-side inproc.
37//
38// The new CLR's use a different set of SEH codes to avoid conflicting with the legacy CLR's.
39// In addition, to distinguish between EH's raised by different inproc instances of the CLR,
40// the module handle of the owning CLR is stored in ExceptionRecord.ExceptionInformation[4].
41//
42// (Note: all existing SEH's use either only slot [0] or no slots at all. We are leaving
43// slots [1] thru [3] open for future expansion.)
44//===========================================================================================
45
46// Is this exception code one of the special CLR-specific SEH codes that participate in the
47// instance-tagging scheme?
48BOOL IsInstanceTaggedSEHCode(DWORD dwExceptionCode);
49
50
51// This set of overloads generates the NumberParameters and ExceptionInformation[] array to
52// pass to RaiseException().
53//
54// Parameters:
55// exceptionArgs: a fixed-size array of size INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE.
56// This will get filled in by this function. (The module handle goes
57// in the last slot if this is a side-by-side-inproc enabled build.)
58//
59// exceptionArg1... up to four arguments that go in slots [0]..[3]. These depends
60// the specific requirements of your exception code.
61//
62// Returns:
63// The NumberParameters to pass to RaiseException().
64//
65// Basically, this is either INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE or the count of your
66// fixed arguments depending on whether this tagged-SEH-enabled build.
67//
68// This function is not permitted to fail.
69
70#define INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE 5
71DWORD MarkAsThrownByUs(/*out*/ ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE]);
72DWORD MarkAsThrownByUs(/*out*/ ULONG_PTR exceptionArgs[INSTANCE_TAGGED_SEH_PARAM_ARRAY_SIZE], ULONG_PTR arg0);
73// (the existing system can support more overloads up to 4 fixed arguments but we don't need them at this time.)
74
75
76// Given an exception record, checks if it's exception code matches a specific exception code
77// *and* whether it was tagged by the calling instance of the CLR.
78//
79// If this is a non-tagged-SEH-enabled build, it is blindly assumed to be tagged by the
80// calling instance of the CLR.
81BOOL WasThrownByUs(const EXCEPTION_RECORD *pcER, DWORD dwExceptionCode);
82
83
84//-----------------------------------------------------------------------------------
85// The following group wraps the basic abstracts specifically for EXCEPTION_COMPLUS.
86//-----------------------------------------------------------------------------------
87BOOL IsComPlusException(const EXCEPTION_RECORD *pcER);
88VOID RaiseComPlusException();
89
90
91//===========================================================================================
92//===========================================================================================
93
94
95//-------------------------------------------------------------------------------------------
96// This routine will generate the most descriptive possible error message for an hresult.
97// It will generate at minimum the hex value. It will also try to generate the symbolic name
98// (E_POINTER) and the friendly description (from the message tables.)
99//
100// bNoGeekStuff suppresses hex HR codes. Use this sparingly as most error strings generated by the
101// CLR are aimed at developers, not end-users.
102//-------------------------------------------------------------------------------------------
103void GetHRMsg(HRESULT hresult, SString &result, BOOL bNoGeekStuff = FALSE);
104
105
106//-------------------------------------------------------------------------------------------
107// Similar to GetHRMsg but phrased for top-level exception message.
108//-------------------------------------------------------------------------------------------
109void GenerateTopLevelHRExceptionMessage(HRESULT hresult, SString &result);
110
111
112// ---------------------------------------------------------------------------
113// We save current ExceptionPointers using VectoredExceptionHandler. The save data is only valid
114// duing exception handling. GetCurrentExceptionPointers returns the saved data.
115// ---------------------------------------------------------------------------
116void GetCurrentExceptionPointers(PEXCEPTION_POINTERS pExceptionInfo);
117
118// ---------------------------------------------------------------------------
119// We save current ExceptionPointers using VectoredExceptionHandler. The save data is only valid
120// duing exception handling. GetCurrentExceptionCode returns the current exception code.
121// ---------------------------------------------------------------------------
122DWORD GetCurrentExceptionCode();
123
124// ---------------------------------------------------------------------------
125// We save current ExceptionPointers using VectoredExceptionHandler. The save data is only valid
126// duing exception handling. Return TRUE if the current exception is hard or soft SO.
127// ---------------------------------------------------------------------------
128bool IsCurrentExceptionSO();
129
130// ---------------------------------------------------------------------------
131// Return TRUE if the current exception is hard( or soft) SO. Soft SO
132// is defined when the stack probing code is enabled (FEATURE_STACK_PROBE)
133// ---------------------------------------------------------------------------
134bool IsSOExceptionCode(DWORD exceptionCode);
135
136// ---------------------------------------------------------------------------
137// Standard exception hierarchy & infrastructure for library code & EE
138// ---------------------------------------------------------------------------
139
140// ---------------------------------------------------------------------------
141// Exception class. Abstract root exception of our hierarchy.
142// ---------------------------------------------------------------------------
143
144class Exception;
145class SEHException;
146
147
148// Exception hierarchy:
149/* GetInstanceType
150Exception
151 |
152 |-> HRException Y
153 | |
154 | |-> HRMsgException
155 | |-> COMException
156 |
157 |-> SEHException Y
158 |
159 |-> DelegatingException Y
160 |
161 |-> StackOverflowException Y
162 |
163 |-> OutOfMemoryException Y
164 |
165 |-> CLRException Y
166 |
167 |-> EEException Y
168 | |
169 | |-> EEMessageException
170 | |
171 | |-> EEResourceException
172 | |
173 | |-> EECOMException
174 | |
175 | |-> EEFieldException
176 | |
177 | |-> EEMethodException
178 | |
179 | |-> EEArgumentException
180 | |
181 | |-> EETypeLoadException
182 | |
183 | |-> EEFileLoadException
184 |
185 |-> ObjrefException Y
186 |
187 |-> CLRLastThrownObjectException Y
188*/
189
190class Exception
191{
192 friend bool DebugIsEECxxExceptionPointer(void* pv);
193
194 private:
195 static const int c_type = 0x524f4f54; // 'ROOT'
196 static Exception * g_OOMException;
197 static Exception * g_SOException;
198
199 protected:
200 Exception *m_innerException;
201
202 public:
203 Exception() {LIMITED_METHOD_DAC_CONTRACT; m_innerException = NULL;}
204 virtual ~Exception() {LIMITED_METHOD_DAC_CONTRACT; if (m_innerException != NULL) Exception::Delete(m_innerException); }
205 virtual BOOL IsDomainBound() {return m_innerException!=NULL && m_innerException->IsDomainBound();} ;
206 virtual HRESULT GetHR() = 0;
207 virtual void GetMessage(SString &s);
208 virtual IErrorInfo *GetErrorInfo() { LIMITED_METHOD_CONTRACT; return NULL; }
209 virtual HRESULT SetErrorInfo() { LIMITED_METHOD_CONTRACT; return S_OK; }
210 void SetInnerException(Exception * pInnerException) { LIMITED_METHOD_CONTRACT; m_innerException = pInnerException; }
211
212 // Dynamic type query for catchers
213 static int GetType() { LIMITED_METHOD_CONTRACT; return c_type; }
214 // !!! If GetInstanceType is implemented, IsSameInstanceType should be implemented
215 virtual int GetInstanceType() = 0;
216 virtual BOOL IsType(int type) {LIMITED_METHOD_CONTRACT; return type == c_type; }
217
218 // This is used in CLRException::GetThrowable to detect if we are in a recursive situation.
219 virtual BOOL IsSameInstanceType(Exception *pException) = 0;
220
221 // Will create a new instance of the Exception. Note that this will
222 // be free of app domain or thread affinity. Not every type of exception
223 // can be cloned with full fidelity.
224 virtual Exception *Clone();
225
226 // DomainBoundClone is a specialized form of cloning which is guaranteed
227 // to provide full fidelity. However, the result is bound to the current
228 // app domain and should not be leaked.
229 Exception *DomainBoundClone();
230
231 class HandlerState
232 {
233 enum CaughtFlags
234 {
235 Caught = 1,
236 CaughtSO = 2,
237 CaughtCxx = 4,
238 };
239
240 DWORD m_dwFlags;
241 public:
242 Exception* m_pExceptionPtr;
243
244 HandlerState();
245
246 void CleanupTry();
247 void SetupCatch(INDEBUG_COMMA(__in_z const char * szFile) int lineNum, bool fVMInitialized = true);
248 void SucceedCatch();
249
250 BOOL DidCatch() { return (m_dwFlags & Caught); }
251 void SetCaught() { m_dwFlags |= Caught; }
252
253 BOOL DidCatchSO() { return (m_dwFlags & CaughtSO); }
254 void SetCaughtSO() { m_dwFlags |= CaughtSO; }
255
256 BOOL DidCatchCxx() { return (m_dwFlags & CaughtCxx); }
257 void SetCaughtCxx() { m_dwFlags |= CaughtCxx; }
258 };
259
260 // Is this exception type considered "uncatchable"?
261 BOOL IsTerminal();
262
263 // Is this exception type considered "transient" (would a retry possibly succeed)?
264 BOOL IsTransient();
265 static BOOL IsTransient(HRESULT hr);
266
267 // Get an HRESULT's source representation, if known
268 static LPCSTR GetHRSymbolicName(HRESULT hr);
269
270 static Exception* GetOOMException();
271
272 // Preallocated exceptions: If there is a preallocated instance of some
273 // subclass of Exception, override this function and return a correct
274 // value. The default implementation returns constant FALSE
275 virtual BOOL IsPreallocatedException();
276 BOOL IsPreallocatedOOMException();
277
278 static void Delete(Exception* pvMemory);
279
280protected:
281
282 // This virtual method must be implemented by any non abstract Exception
283 // derived class. It must allocate a NEW exception of the identical type and
284 // copy all the relevant fields from the current exception to the new one.
285 // It is NOT responsible however for copying the inner exception. This
286 // will be handled by the base Exception class.
287 virtual Exception *CloneHelper();
288
289 // This virtual method must be implemented by Exception subclasses whose
290 // DomainBoundClone behavior is different than their normal clone behavior.
291 // It must allocate a NEW exception of the identical type and
292 // copy all the relevant fields from the current exception to the new one.
293 // It is NOT responsible however for copying the inner exception. This
294 // will be handled by the base Exception class.
295 virtual Exception *DomainBoundCloneHelper() { return CloneHelper(); }
296};
297
298#if 1
299template <typename T>
300inline void Exception__Delete(T* pvMemory);
301
302template <>
303inline void Exception__Delete<Exception>(Exception* pvMemory)
304{
305 Exception::Delete(pvMemory);
306}
307
308NEW_WRAPPER_TEMPLATE1(ExceptionHolderTemplate, Exception__Delete<_TYPE>);
309typedef ExceptionHolderTemplate<Exception> ExceptionHolder;
310#else
311
312//------------------------------------------------------------------------------
313// class ExceptionHolder
314//
315// This is a very lightweight holder class for use inside the EX_TRY family
316// of macros. It is based on the standard Holder classes, but has been
317// highly specialized for this one function, so that extra code can be
318// removed, and the resulting code can be simple enough for all of the
319// non-exceptional-case code to be inlined.
320class ExceptionHolder
321{
322private:
323 Exception *m_value;
324 BOOL m_acquired;
325
326public:
327 FORCEINLINE ExceptionHolder(Exception *pException = NULL, BOOL take = TRUE)
328 : m_value(pException)
329 {
330 m_acquired = pException && take;
331 }
332
333 FORCEINLINE ~ExceptionHolder()
334 {
335 if (m_acquired)
336 {
337 Exception::Delete(m_value);
338 }
339 }
340
341 Exception* operator->() { return m_value; }
342
343 void operator=(Exception *p)
344 {
345 Release();
346 m_value = p;
347 Acquire();
348 }
349
350 BOOL IsNull() { return m_value == NULL; }
351
352 operator Exception*() { return m_value; }
353
354 Exception* GetValue() { return m_value; }
355
356 void SuppressRelease() { m_acquired = FALSE; }
357
358private:
359 void Acquire()
360 {
361 _ASSERTE(!m_acquired);
362
363 if (!IsNull())
364 {
365 m_acquired = TRUE;
366 }
367 }
368 void Release()
369 {
370 if (m_acquired)
371 {
372 _ASSERTE(!IsNull());
373 Exception::Delete(m_value);
374 m_acquired = FALSE;
375 }
376 }
377
378};
379
380#endif
381
382// ---------------------------------------------------------------------------
383// HRException class. Implements exception API for exceptions generated from HRESULTs
384// ---------------------------------------------------------------------------
385
386class HRException : public Exception
387{
388 friend bool DebugIsEECxxExceptionPointer(void* pv);
389
390 protected:
391 HRESULT m_hr;
392
393 public:
394 HRException();
395 HRException(HRESULT hr);
396
397 static const int c_type = 0x48522020; // 'HR '
398
399 // Dynamic type query for catchers
400 static int GetType() {LIMITED_METHOD_DAC_CONTRACT; return c_type; }
401 virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
402 virtual BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type); }
403 // Virtual overrides
404 HRESULT GetHR();
405
406 BOOL IsSameInstanceType(Exception *pException)
407 {
408 WRAPPER_NO_CONTRACT;
409 return pException->GetInstanceType() == GetType() && pException->GetHR() == m_hr;
410 }
411
412 protected:
413 virtual Exception *CloneHelper()
414 {
415 WRAPPER_NO_CONTRACT;
416 return new HRException(m_hr);
417 }
418};
419
420// ---------------------------------------------------------------------------
421// HRMessageException class. Implements exception API for exceptions
422// generated from HRESULTs, and includes in info message.
423// ---------------------------------------------------------------------------
424
425class HRMsgException : public HRException
426{
427 friend bool DebugIsEECxxExceptionPointer(void* pv);
428
429 protected:
430 SString m_msg;
431
432 public:
433 HRMsgException();
434 HRMsgException(HRESULT hr, SString const &msg);
435
436 // Virtual overrides
437 void GetMessage(SString &s);
438
439 protected:
440 virtual Exception *CloneHelper()
441 {
442 WRAPPER_NO_CONTRACT;
443 return new HRMsgException(m_hr, m_msg);
444 }
445};
446
447// ---------------------------------------------------------------------------
448// COMException class. Implements exception API for standard COM-based error info
449// ---------------------------------------------------------------------------
450
451class COMException : public HRException
452{
453 friend bool DebugIsEECxxExceptionPointer(void* pv);
454
455 private:
456 IErrorInfo *m_pErrorInfo;
457
458 public:
459 COMException();
460 COMException(HRESULT hr) ;
461 COMException(HRESULT hr, IErrorInfo *pErrorInfo);
462 ~COMException();
463
464 // Virtual overrides
465 IErrorInfo *GetErrorInfo();
466 void GetMessage(SString &result);
467
468 protected:
469 virtual Exception *CloneHelper()
470 {
471 WRAPPER_NO_CONTRACT;
472 return new COMException(m_hr, m_pErrorInfo);
473 }
474};
475
476// ---------------------------------------------------------------------------
477// SEHException class. Implements exception API for SEH exception info
478// ---------------------------------------------------------------------------
479
480class SEHException : public Exception
481{
482 friend bool DebugIsEECxxExceptionPointer(void* pv);
483
484 public:
485 EXCEPTION_RECORD m_exception;
486
487 SEHException();
488 SEHException(EXCEPTION_RECORD *pRecord, T_CONTEXT *pContext = NULL);
489
490 static const int c_type = 0x53454820; // 'SEH '
491
492 // Dynamic type query for catchers
493 static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; }
494 virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
495 virtual BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type); }
496
497 BOOL IsSameInstanceType(Exception *pException)
498 {
499 WRAPPER_NO_CONTRACT;
500 return pException->GetInstanceType() == GetType() && pException->GetHR() == GetHR();
501 }
502
503 // Virtual overrides
504 HRESULT GetHR();
505 IErrorInfo *GetErrorInfo();
506 void GetMessage(SString &result);
507
508 protected:
509 virtual Exception *CloneHelper()
510 {
511 WRAPPER_NO_CONTRACT;
512 return new SEHException(&m_exception);
513 }
514};
515
516// ---------------------------------------------------------------------------
517// DelegatingException class. Implements exception API for "foreign" exceptions.
518// ---------------------------------------------------------------------------
519
520class DelegatingException : public Exception
521{
522 Exception *m_delegatedException;
523 Exception* GetDelegate();
524
525 enum {DELEGATE_NOT_YET_SET = -1};
526 bool IsDelegateSet() {LIMITED_METHOD_DAC_CONTRACT; return m_delegatedException != (Exception*)DELEGATE_NOT_YET_SET; }
527 bool IsDelegateValid() {LIMITED_METHOD_DAC_CONTRACT; return IsDelegateSet() && m_delegatedException != NULL; }
528
529 public:
530
531 DelegatingException();
532 ~DelegatingException();
533
534 static const int c_type = 0x44454C20; // 'DEL '
535
536 // Dynamic type query for catchers
537 static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; }
538 virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
539 virtual BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type); }
540
541 BOOL IsSameInstanceType(Exception *pException)
542 {
543 WRAPPER_NO_CONTRACT;
544 return pException->GetInstanceType() == GetType() && pException->GetHR() == GetHR();
545 }
546
547 // Virtual overrides
548 virtual BOOL IsDomainBound() {return Exception::IsDomainBound() ||(m_delegatedException!=NULL && m_delegatedException->IsDomainBound());} ;
549 HRESULT GetHR();
550 IErrorInfo *GetErrorInfo();
551 void GetMessage(SString &result);
552 virtual Exception *Clone();
553
554 protected:
555 virtual Exception *CloneHelper()
556 {
557 WRAPPER_NO_CONTRACT;
558 return new DelegatingException();
559 }
560};
561
562//------------------------------------------------------------------------------
563// class OutOfMemoryException
564//
565// While there could be any number of instances of this class, there is one
566// special instance, the pre-allocated OOM exception. Storage for that
567// instance is allocated in the image, so we can always obtain it, even
568// in low memory situations.
569// Note that, in fact, there is only one instance.
570//------------------------------------------------------------------------------
571class OutOfMemoryException : public Exception
572{
573 private:
574 static const int c_type = 0x4F4F4D20; // 'OOM '
575 BOOL bIsPreallocated;
576
577 public:
578 OutOfMemoryException() : bIsPreallocated(FALSE) {}
579 OutOfMemoryException(BOOL b) : bIsPreallocated(b) {}
580
581 // Dynamic type query for catchers
582 static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; }
583 virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; }
584 BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type); }
585
586 BOOL IsSameInstanceType(Exception *pException)
587 {
588 WRAPPER_NO_CONTRACT;
589 return pException->GetInstanceType() == GetType();
590 }
591
592 HRESULT GetHR() {LIMITED_METHOD_DAC_CONTRACT; return E_OUTOFMEMORY; }
593 void GetMessage(SString &result) { WRAPPER_NO_CONTRACT; result.SetASCII("Out Of Memory"); }
594
595 virtual Exception *Clone();
596
597 virtual BOOL IsPreallocatedException() { return bIsPreallocated; }
598};
599
600template <typename STATETYPE>
601class CAutoTryCleanup
602{
603public:
604 DEBUG_NOINLINE CAutoTryCleanup(STATETYPE& refState) :
605 m_refState(refState)
606 {
607 SCAN_SCOPE_BEGIN;
608 STATIC_CONTRACT_THROWS;
609 STATIC_CONTRACT_SUPPORTS_DAC;
610
611#ifdef ENABLE_CONTRACTS_IMPL
612 // This is similar to ClrTryMarkerHolder. We're marking that its okay to throw on this thread now because
613 // we're within a try block. We fold this into here strictly for performance reasons... we have one
614 // stack-allocated object do the work.
615 m_pClrDebugState = GetClrDebugState();
616 m_oldOkayToThrowValue = m_pClrDebugState->IsOkToThrow();
617 m_pClrDebugState->SetOkToThrow();
618#endif
619 }
620
621 DEBUG_NOINLINE ~CAutoTryCleanup()
622 {
623 SCAN_SCOPE_END;
624 WRAPPER_NO_CONTRACT;
625
626 m_refState.CleanupTry();
627
628#ifdef ENABLE_CONTRACTS_IMPL
629 // Restore the original OkayToThrow value since we're leaving the try block.
630
631 m_pClrDebugState->SetOkToThrow( m_oldOkayToThrowValue );
632#endif // ENABLE_CONTRACTS_IMPL
633 }
634
635protected:
636 STATETYPE& m_refState;
637
638#ifdef ENABLE_CONTRACTS_DATA
639private:
640 BOOL m_oldOkayToThrowValue;
641 ClrDebugState *m_pClrDebugState;
642#endif
643};
644
645// ---------------------------------------------------------------------------
646// Throw/Catch macros
647//
648// Usage:
649//
650// EX_TRY
651// {
652// EX_THROW(HRException, (E_FAIL));
653// }
654// EX_CATCH
655// {
656// Exception *e = GET_EXCEPTION();
657// EX_RETHROW;
658// }
659// EX_END_CATCH(RethrowTerminalExceptions, RethrowTransientExceptions or SwallowAllExceptions)
660//
661// ---------------------------------------------------------------------------
662
663// ---------------------------------------------------------------------------
664// #NO_HOST_CPP_EH_ONLY
665//
666// The EX_CATCH* macros defined below can work one of two ways:
667// 1. They catch all exceptions, both C++ and SEH exceptions.
668// 2. They catch only C++ exceptions.
669//
670// Which way they are defined depends on what sort of handling of SEH
671// exceptions, like AV's, you wish to have in your DLL. In general we
672// do not typically want to catch and swallow AV's.
673//
674// By default, the macros catch all exceptions. This is how they work when
675// compiled into the primary runtime DLL (clr.dll). This is reasonable for
676// the CLR becuase it needs to also catch managed exceptions, which are SEH
677// exceptions, and because that DLL also includes a vectored exception
678// handler that will take down the process on any AV within clr.dll.
679//
680// But for uses of these macros outside of the CLR DLL there are other
681// possibilities. If a DLL only uses facilities in Utilcode that throw the
682// C++ exceptions defined above, and never needs to catch a managed exception,
683// then that DLL should setup the macros to only catch C++ exceptions. That
684// way, AV's are not accidentally swallowed and hidden.
685//
686// On the other hand, if a DLL needs to catch managed exceptions, then it has
687// no choice but to also catch all SEH exceptions, including AV's. In that case
688// the DLL should also include a vectored handler, like CLR.dll, to take the
689// process down on an AV.
690//
691// The behavior difference is controled by NO_HOST_CPP_EH_ONLY. When defined,
692// the EX_CATCH* macros only catch C++ exceptions. When not defined, they catch
693// C++ and SEH exceptions.
694//
695// Note: use of NO_HOST_CPP_EH_ONLY is only valid outside the primary CLR DLLs.
696// Thus it is an error to attempt to define it without also defining SELF_NO_HOST.
697// ---------------------------------------------------------------------------
698
699#if defined(NO_HOST_CPP_EH_ONLY) && !defined(SELF_NO_HOST)
700#error It is incorrect to attempt to have C++-only EH macros when hosted. This is only valid for components outside the runtime DLLs.
701#endif
702
703//-----------------------------------------------------------------------
704// EX_END_CATCH has a mandatory argument which is one of "RethrowTerminalExceptions",
705// "RethrowTransientExceptions", or "SwallowAllExceptions".
706//
707// If an exception is considered "terminal" (e->IsTerminal()), it should normally
708// be allowed to proceed. Hence, most of the time, you should use RethrowTerminalExceptions.
709//
710// In some cases you will want transient exceptions (terminal plus things like
711// resource exhaustion) to proceed as well. Use RethrowTransientExceptions for this cas.
712//
713// If you have a good reason to use SwallowAllExceptions, (e.g. a hard COM interop boundary)
714// use one of the higher level macros for this if available, or consider developing one.
715// Otherwise, clearly document why you're swallowing terminal exceptions. Raw uses of
716// SwallowAllExceptions will cause the cleanup police to come knocking on your door
717// at some point.
718//
719// A lot of existing TRY's swallow terminals right now simply because there is
720// backout code following the END_CATCH that has to be executed. The solution is
721// to replace that backout code with holder objects.
722
723//-----------------------------------------------------------------------
724
725#define RethrowTransientExceptions \
726 if (GET_EXCEPTION()->IsTransient()) \
727 { \
728 EX_RETHROW; \
729 } \
730
731#define RethrowSOExceptions \
732 if (__state.DidCatchSO()) \
733 { \
734 STATIC_CONTRACT_THROWS_TERMINAL; \
735 EX_RETHROW; \
736 } \
737
738
739// Don't use this - use RethrowCorruptingExceptions (see below) instead.
740#define SwallowAllExceptions ;
741
742//////////////////////////////////////////////////////////////////////
743//
744// Corrupted State Exception Support
745//
746/////////////////////////////////////////////////////////////////////
747
748#ifdef FEATURE_CORRUPTING_EXCEPTIONS
749
750#define CORRUPTING_EXCEPTIONS_ONLY(expr) expr
751#define COMMA_CORRUPTING_EXCEPTIONS_ONLY(expr) ,expr
752
753// EX_END_CATCH has been modified to not swallow Corrupting Exceptions (CE) when one of the
754// following arguments are passed to it:
755//
756// 1) RethrowTerminalExceptions - rethrows both terminal and corrupting exceptions
757// 2) RethrowCorruptingExceptions - swallows all exceptions exception corrupting exceptions. This SHOULD BE USED instead of SwallowAllExceptions.
758// 3) RethrowTerminalExceptionsEx - same as (1) but rethrow of CE can be controlled via a condition.
759// 4) RethrowCorruptingExceptionsEx - same as (2) but rethrow of CE can be controlled via a condition.
760//
761// By default, if a CE is encountered when one of the above policies are applied, the runtime will
762// ensure that the CE propagates up the stack and not get swallowed unless the developer chooses to override the behaviour.
763// This can be done by using the "Ex" versions above that take a conditional which evaluates to a BOOL. In such a case,
764// the CE will *only* be rethrown if the conditional evalutes to TRUE. For examples, refer to COMToCLRWorker or
765// DispatchInfo::InvokeMember implementations.
766//
767// SET_CE_RETHROW_FLAG_FOR_EX_CATCH macros helps evaluate if the CE is to be rethrown or not. This has been redefined in
768// Clrex.h to add the condition of evaluating the throwable as well (which is not available outside the VM folder).
769//
770// Typically, SET_CE_RETHROW_FLAG_FOR_EX_CATCH would rethrow a Corrupted State Exception. However, SO needs to be dealt
771// with specially and this work is done during EX_CATCH, by calling SetupCatch against the handler state, and by EX_ENDTRY
772// by calling HANDLE_STACKOVERFLOW_AFTER_CATCH.
773//
774// Passing FALSE as the second argument to IsProcessCorruptedStateException implies that SET_CE_RETHROW_FLAG_FOR_EX_CATCH
775// will ensure that we dont rethrow SO and allow EX_ENDTRY to SO specific processing. If none is done, then EX_ENDTRY will
776// rethrow SO. By that time stack has been reclaimed and thus, throwing SO will be safe.
777//
778// We also check the global override flag incase it has been set to force pre-V4 beahviour. "0" implies it has not
779// been overriden.
780#define SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr) (((expr == TRUE) && \
781 (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy) == 0) && \
782 IsProcessCorruptedStateException(GetCurrentExceptionCode(), FALSE)))
783
784// This rethrow policy can be used in EX_END_CATCH to swallow all exceptions except the corrupting ones.
785// This macro can be used to rethrow the CE based upon a BOOL condition.
786#define RethrowCorruptingExceptionsEx(expr) \
787 if (SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr)) \
788 { \
789 STATIC_CONTRACT_THROWS_TERMINAL; \
790 EX_RETHROW; \
791 }
792
793#define RethrowCorruptingExceptionsExAndHookRethrow(shouldRethrowExpr, aboutToRethrowExpr) \
794 if (SET_CE_RETHROW_FLAG_FOR_EX_CATCH(shouldRethrowExpr)) \
795 { \
796 STATIC_CONTRACT_THROWS_TERMINAL; \
797 aboutToRethrowExpr; \
798 EX_RETHROW; \
799 }
800
801#else // !FEATURE_CORRUPTING_EXCEPTIONS
802
803#define CORRUPTING_EXCEPTIONS_ONLY(expr)
804#define COMMA_CORRUPTING_EXCEPTIONS_ONLY(expr)
805
806// When we dont have support for CE, just map it to SwallowAllExceptions
807#define RethrowCorruptingExceptionsEx(expr) SwallowAllExceptions
808#define RethrowCorruptingExceptionsExAndHookRethrow(shouldRethrowExpr, aboutToRethrowExpr) SwallowAllExceptions
809#define SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr) !TRUE
810#endif // FEATURE_CORRUPTING_EXCEPTIONS
811
812// Map to RethrowCorruptingExceptionsEx so that it does the "right" thing
813#define RethrowCorruptingExceptions RethrowCorruptingExceptionsEx(TRUE)
814
815// This macro can be used to rethrow the CE based upon a BOOL condition. It will continue to rethrow terminal
816// exceptions unconditionally.
817#define RethrowTerminalExceptionsEx(expr) \
818 if (GET_EXCEPTION()->IsTerminal() || \
819 SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr)) \
820 { \
821 STATIC_CONTRACT_THROWS_TERMINAL; \
822 EX_RETHROW; \
823 } \
824
825
826// When applied to EX_END_CATCH, this policy will always rethrow Terminal and Corrupting exceptions if they are
827// encountered.
828#define RethrowTerminalExceptions RethrowTerminalExceptionsEx(TRUE)
829
830// Special define to be used in EEStartup that will also check for VM initialization before
831// commencing on a path that may use the managed thread object.
832#define RethrowTerminalExceptionsWithInitCheck \
833 if ((g_fEEStarted == TRUE) && (GetThread() != NULL)) \
834 { \
835 RethrowTerminalExceptions \
836 }
837
838#ifdef _DEBUG
839
840void ExThrowTrap(const char *fcn, const char *file, int line, const char *szType, HRESULT hr, const char *args);
841
842#define EX_THROW_DEBUG_TRAP(fcn, file, line, szType, hr, args) ExThrowTrap(fcn, file, line, szType, hr, args)
843
844#else
845
846#define EX_THROW_DEBUG_TRAP(fcn, file, line, szType, hr, args)
847
848#endif
849
850#define HANDLE_SO_TOLERANCE_FOR_THROW
851
852#define EX_THROW(_type, _args) \
853 { \
854 FAULT_NOT_FATAL(); \
855 \
856 HANDLE_SO_TOLERANCE_FOR_THROW; \
857 _type * ___pExForExThrow = new _type _args ; \
858 /* don't embed file names in retail to save space and avoid IP */ \
859 /* a findstr /n will allow you to locate it in a pinch */ \
860 STRESS_LOG3(LF_EH, LL_INFO100, "EX_THROW Type = 0x%x HR = 0x%x, " \
861 INDEBUG(__FILE__) " line %d\n", _type::GetType(), \
862 ___pExForExThrow->GetHR(), __LINE__); \
863 EX_THROW_DEBUG_TRAP(__FUNCTION__, __FILE__, __LINE__, #_type, ___pExForExThrow->GetHR(), #_args); \
864 PAL_CPP_THROW(_type *, ___pExForExThrow); \
865 }
866
867//--------------------------------------------------------------------------------
868// Clones an exception into the current domain. Also handles special cases for
869// OOM and other stuff. Making this a function so we don't inline all this logic
870// every place we call EX_THROW_WITH_INNER.
871//--------------------------------------------------------------------------------
872Exception *ExThrowWithInnerHelper(Exception *inner);
873
874// This macro will set the m_innerException into the newly created exception
875// The passed in _type has to be derived from CLRException. You cannot put OOM
876// as the inner exception. If we are throwing in OOM case, allocate more memory (this macro will clone)
877// does not make any sense.
878//
879#define EX_THROW_WITH_INNER(_type, _args, _inner) \
880 { \
881 FAULT_NOT_FATAL(); \
882 \
883 HANDLE_SO_TOLERANCE_FOR_THROW; \
884 Exception *_inner2 = ExThrowWithInnerHelper(_inner); \
885 _type *___pExForExThrow = new _type _args ; \
886 ___pExForExThrow->SetInnerException(_inner2); \
887 STRESS_LOG3(LF_EH, LL_INFO100, "EX_THROW_WITH_INNER Type = 0x%x HR = 0x%x, " \
888 INDEBUG(__FILE__) " line %d\n", _type::GetType(), \
889 ___pExForExThrow->GetHR(), __LINE__); \
890 EX_THROW_DEBUG_TRAP(__FUNCTION__, __FILE__, __LINE__, #_type, ___pExForExThrow->GetHR(), #_args); \
891 PAL_CPP_THROW(_type *, ___pExForExThrow); \
892 }
893
894//#define IsCLRException(ex) ((ex !=NULL) && ex->IsType(CLRException::GetType())
895
896#define EX_TRY_IMPL EX_TRY_CUSTOM(Exception::HandlerState, , DelegatingException /* was SEHException*/)
897
898#define EX_TRY_CPP_ONLY EX_TRY_CUSTOM_CPP_ONLY(Exception::HandlerState, , DelegatingException /* was SEHException*/)
899
900#ifndef INCONTRACT
901#ifdef ENABLE_CONTRACTS
902#define INCONTRACT(x) x
903#else
904#define INCONTRACT(x)
905#endif
906#endif
907
908#define EX_TRY_CUSTOM(STATETYPE, STATEARG, DEFAULT_EXCEPTION_TYPE) \
909 { \
910 STATETYPE __state STATEARG; \
911 typedef DEFAULT_EXCEPTION_TYPE __defaultException_t; \
912 SCAN_EHMARKER(); \
913 PAL_CPP_TRY \
914 { \
915 SCAN_EHMARKER_TRY(); \
916 SCAN_EHMARKER(); \
917 PAL_CPP_TRY \
918 { \
919 SCAN_EHMARKER_TRY(); \
920 CAutoTryCleanup<STATETYPE> __autoCleanupTry(__state); \
921 /* prevent annotations from being dropped by optimizations in debug */ \
922 INDEBUG(static bool __alwayszero;) \
923 INDEBUG(VolatileLoad(&__alwayszero);) \
924 { \
925 /* Disallow returns to make exception handling work. */ \
926 /* Some work is done after the catch, see EX_ENDTRY. */ \
927 DEBUG_ASSURE_NO_RETURN_BEGIN(EX_TRY) \
928 EX_TRY_HOLDER \
929
930
931#define EX_CATCH_IMPL_EX(DerivedExceptionClass) \
932 DEBUG_ASSURE_NO_RETURN_END(EX_TRY) \
933 } \
934 SCAN_EHMARKER_END_TRY(); \
935 } \
936 PAL_CPP_CATCH_DERIVED (DerivedExceptionClass, __pExceptionRaw) \
937 { \
938 SCAN_EHMARKER_CATCH(); \
939 __state.SetCaughtCxx(); \
940 __state.m_pExceptionPtr = __pExceptionRaw; \
941 SCAN_EHMARKER_END_CATCH(); \
942 SCAN_IGNORE_THROW_MARKER; \
943 PAL_CPP_RETHROW; \
944 } \
945 PAL_CPP_ENDTRY \
946 SCAN_EHMARKER_END_TRY(); \
947 } \
948 PAL_CPP_CATCH_ALL \
949 { \
950 SCAN_EHMARKER_CATCH(); \
951 VALIDATE_BACKOUT_STACK_CONSUMPTION; \
952 __defaultException_t __defaultException; \
953 CHECK::ResetAssert(); \
954 ExceptionHolder __pException(__state.m_pExceptionPtr); \
955 /* work around unreachable code warning */ \
956 if (true) { \
957 DEBUG_ASSURE_NO_RETURN_BEGIN(EX_CATCH) \
958 /* don't embed file names in retail to save space and avoid IP */ \
959 /* a findstr /n will allow you to locate it in a pinch */ \
960 __state.SetupCatch(INDEBUG_COMMA(__FILE__) __LINE__); \
961
962#define EX_CATCH_IMPL EX_CATCH_IMPL_EX(Exception)
963
964#define EX_TRY_CUSTOM_CPP_ONLY(STATETYPE, STATEARG, DEFAULT_EXCEPTION_TYPE) \
965 { \
966 STATETYPE __state STATEARG; \
967 typedef DEFAULT_EXCEPTION_TYPE __defaultException_t; \
968 SCAN_EHMARKER(); \
969 PAL_CPP_TRY \
970 { \
971 SCAN_EHMARKER_TRY(); \
972 CAutoTryCleanup<STATETYPE> __autoCleanupTry(__state); \
973 /* prevent annotations from being dropped by optimizations in debug */ \
974 INDEBUG(static bool __alwayszero;) \
975 INDEBUG(VolatileLoad(&__alwayszero);) \
976 { \
977 /* Disallow returns to make exception handling work. */ \
978 /* Some work is done after the catch, see EX_ENDTRY. */ \
979 DEBUG_ASSURE_NO_RETURN_BEGIN(EX_TRY) \
980
981#define EX_CATCH_IMPL_CPP_ONLY \
982 DEBUG_ASSURE_NO_RETURN_END(EX_TRY) \
983 } \
984 SCAN_EHMARKER_END_TRY(); \
985 } \
986 PAL_CPP_CATCH_DERIVED (Exception, __pExceptionRaw) \
987 { \
988 SCAN_EHMARKER_CATCH(); \
989 __state.SetCaughtCxx(); \
990 __state.m_pExceptionPtr = __pExceptionRaw; \
991 SCAN_EHMARKER_END_CATCH(); \
992 SCAN_IGNORE_THROW_MARKER; \
993 VALIDATE_BACKOUT_STACK_CONSUMPTION; \
994 __defaultException_t __defaultException; \
995 CHECK::ResetAssert(); \
996 ExceptionHolder __pException(__state.m_pExceptionPtr); \
997 /* work around unreachable code warning */ \
998 if (true) { \
999 DEBUG_ASSURE_NO_RETURN_BEGIN(EX_CATCH) \
1000 /* don't embed file names in retail to save space and avoid IP */ \
1001 /* a findstr /n will allow you to locate it in a pinch */ \
1002 __state.SetupCatch(INDEBUG_COMMA(__FILE__) __LINE__); \
1003
1004
1005// Here we finally define the EX_CATCH* macros that will be used throughout the system.
1006// These can catch C++ and SEH exceptions, or just C++ exceptions.
1007// See code:NO_HOST_CPP_EH_ONLY for more details.
1008//
1009// Note: we make it illegal to use forms that are redundant with the basic EX_CATCH
1010// version. I.e., in the C++ & SEH version, EX_CATCH_CPP_AND_SEH is the same as EX_CATCH.
1011// Likewise, in the C++ only version, EX_CATCH_CPP_ONLY is redundant with EX_CATCH.
1012
1013#ifndef NO_HOST_CPP_EH_ONLY
1014#define EX_TRY EX_TRY_IMPL
1015#define EX_CATCH EX_CATCH_IMPL
1016#define EX_CATCH_EX EX_CATCH_IMPL_EX
1017#define EX_CATCH_CPP_ONLY EX_CATCH_IMPL_CPP_ONLY
1018#define EX_CATCH_CPP_AND_SEH Dont_Use_EX_CATCH_CPP_AND_SEH
1019#else
1020#define EX_TRY EX_TRY_CPP_ONLY
1021#define EX_CATCH EX_CATCH_IMPL_CPP_ONLY
1022#define EX_CATCH_CPP_ONLY Dont_Use_EX_CATCH_CPP_ONLY
1023#define EX_CATCH_CPP_AND_SEH EX_CATCH_IMPL
1024
1025// Note: at this time we don't have a use case for EX_CATCH_EX, and we do not have
1026// the C++-only version of the implementation available. Thus we disallow its use at this time.
1027// If a real use case arises then we should go ahead and enable this.
1028#define EX_CATCH_EX Dont_Use_EX_CATCH_EX
1029#endif
1030
1031#define EX_END_CATCH_UNREACHABLE \
1032 DEBUG_ASSURE_NO_RETURN_END(EX_CATCH) \
1033 } \
1034 SCAN_EHMARKER_END_CATCH(); \
1035 UNREACHABLE(); \
1036 } \
1037 PAL_CPP_ENDTRY \
1038 } \
1039
1040
1041// "terminalexceptionpolicy" must be one of "RethrowTerminalExceptions",
1042// "RethrowTransientExceptions", or "SwallowAllExceptions"
1043
1044#define EX_END_CATCH(terminalexceptionpolicy) \
1045 terminalexceptionpolicy; \
1046 __state.SucceedCatch(); \
1047 DEBUG_ASSURE_NO_RETURN_END(EX_CATCH) \
1048 } \
1049 SCAN_EHMARKER_END_CATCH(); \
1050 } \
1051 EX_ENDTRY \
1052 } \
1053
1054
1055#define EX_END_CATCH_FOR_HOOK \
1056 __state.SucceedCatch(); \
1057 DEBUG_ASSURE_NO_RETURN_END(EX_CATCH) \
1058 ANNOTATION_HANDLER_END; \
1059 } \
1060 SCAN_EHMARKER_END_CATCH(); \
1061 } \
1062 EX_ENDTRY \
1063
1064#define EX_ENDTRY \
1065 PAL_CPP_ENDTRY \
1066 if (__state.DidCatch()) \
1067 { \
1068 RESTORE_SO_TOLERANCE_STATE; \
1069 } \
1070 if (__state.DidCatchSO()) \
1071 { \
1072 HANDLE_STACKOVERFLOW_AFTER_CATCH; \
1073 }
1074
1075#define EX_RETHROW \
1076 { \
1077 __pException.SuppressRelease(); \
1078 PAL_CPP_RETHROW; \
1079 } \
1080
1081 // Define a copy of GET_EXCEPTION() that will not be redefined by clrex.h
1082#define GET_EXCEPTION() (__pException == NULL ? &__defaultException : __pException.GetValue())
1083#define EXTRACT_EXCEPTION() (__pException.Extract())
1084
1085
1086//==============================================================================
1087// High-level macros for common uses of EX_TRY. Try using these rather
1088// than the raw EX_TRY constructs.
1089//==============================================================================
1090
1091//===================================================================================
1092// Macro for converting exceptions into HR internally. Unlike EX_CATCH_HRESULT,
1093// it does not set up IErrorInfo on the current thread.
1094//
1095// Usage:
1096//
1097// HRESULT hr = S_OK;
1098// EX_TRY
1099// <do managed stuff>
1100// EX_CATCH_HRESULT_NO_ERRORINFO(hr);
1101// return hr;
1102//
1103// Comments:
1104// Since IErrorInfo is not set up, this does not require COM interop to be started.
1105//===================================================================================
1106
1107#define EX_CATCH_HRESULT_NO_ERRORINFO(_hr) \
1108 EX_CATCH \
1109 { \
1110 (_hr) = GET_EXCEPTION()->GetHR(); \
1111 _ASSERTE(FAILED(_hr)); \
1112 } \
1113 EX_END_CATCH(SwallowAllExceptions)
1114
1115
1116//===================================================================================
1117// Macro for catching managed exception object.
1118//
1119// Usage:
1120//
1121// OBJECTREF pThrowable = NULL;
1122// EX_TRY
1123// <do managed stuff>
1124// EX_CATCH_THROWABLE(&pThrowable);
1125//
1126//===================================================================================
1127
1128#define EX_CATCH_THROWABLE(ppThrowable) \
1129 EX_CATCH \
1130 { \
1131 if (NULL != ppThrowable) \
1132 { \
1133 *ppThrowable = GET_THROWABLE(); \
1134 } \
1135 } \
1136 EX_END_CATCH(SwallowAllExceptions)
1137
1138
1139#ifdef FEATURE_COMINTEROP
1140
1141//===================================================================================
1142// Macro for defining external entrypoints such as COM interop boundaries.
1143// The boundary will catch all exceptions (including terminals) and convert
1144// them into HR/IErrorInfo pairs as appropriate.
1145//
1146// Usage:
1147//
1148// HRESULT hr = S_OK;
1149// EX_TRY
1150// <do managed stuff>
1151// EX_CATCH_HRESULT(hr);
1152// return hr;
1153//
1154// Comments:
1155// Note that IErrorInfo will automatically be set up on the thread if appropriate.
1156//===================================================================================
1157
1158#define EX_CATCH_HRESULT(_hr) \
1159 EX_CATCH \
1160 { \
1161 (_hr) = GET_EXCEPTION()->GetHR(); \
1162 _ASSERTE(FAILED(_hr)); \
1163 IErrorInfo *pErr = GET_EXCEPTION()->GetErrorInfo(); \
1164 if (pErr != NULL) \
1165 { \
1166 SetErrorInfo(0, pErr); \
1167 pErr->Release(); \
1168 } \
1169 } \
1170 EX_END_CATCH(SwallowAllExceptions)
1171
1172//===================================================================================
1173// Macro to make conditional catching more succinct.
1174//
1175// Usage:
1176//
1177// EX_TRY
1178// ...
1179// EX_CATCH_HRESULT_IF(IsHRESULTForExceptionKind(GET_EXCEPTION()->GetHR(), kFileNotFoundException));
1180//===================================================================================
1181
1182#define EX_CATCH_HRESULT_IF(HR, ...) \
1183 EX_CATCH \
1184 { \
1185 (HR) = GET_EXCEPTION()->GetHR(); \
1186 \
1187 /* Rethrow if condition is false. */ \
1188 if (!(__VA_ARGS__)) \
1189 EX_RETHROW; \
1190 \
1191 _ASSERTE(FAILED(HR)); \
1192 IErrorInfo *pErr = GET_EXCEPTION()->GetErrorInfo(); \
1193 if (pErr != NULL) \
1194 { \
1195 SetErrorInfo(0, pErr); \
1196 pErr->Release(); \
1197 } \
1198 } \
1199 EX_END_CATCH(SwallowAllExceptions)
1200
1201#else // FEATURE_COMINTEROP
1202
1203#define EX_CATCH_HRESULT(_hr) EX_CATCH_HRESULT_NO_ERRORINFO(_hr)
1204
1205#endif // FEATURE_COMINTEROP
1206
1207//===================================================================================
1208// Macro for containing normal exceptions but letting terminal exceptions continue to propagate.
1209//
1210// Usage:
1211//
1212// EX_TRY
1213// {
1214// ...your stuff...
1215// }
1216// EX_SWALLOW_NONTERMINAL
1217//
1218// Remember, terminal exceptions (such as ThreadAbort) will still throw out of this
1219// block. So don't use this as a substitute for exception-safe cleanup!
1220//===================================================================================
1221
1222#define EX_SWALLOW_NONTERMINAL \
1223 EX_CATCH \
1224 { \
1225 } \
1226 EX_END_CATCH(RethrowTerminalExceptions) \
1227
1228
1229//===================================================================================
1230// Macro for containing normal exceptions but letting transient exceptions continue to propagate.
1231//
1232// Usage:
1233//
1234// EX_TRY
1235// {
1236// ...your stuff...
1237// }
1238// EX_SWALLOW_NONTRANSIENT
1239//
1240// Terminal exceptions (such as ThreadAbort and OutOfMemory) will still throw out of this
1241// block. So don't use this as a substitute for exception-safe cleanup!
1242//===================================================================================
1243
1244#define EX_SWALLOW_NONTRANSIENT \
1245 EX_CATCH \
1246 { \
1247 } \
1248 EX_END_CATCH(RethrowTransientExceptions) \
1249
1250
1251//===================================================================================
1252// Macro for observing or wrapping exceptions in flight.
1253//
1254// Usage:
1255//
1256// EX_TRY
1257// {
1258// ... your stuff ...
1259// }
1260// EX_HOOK
1261// {
1262// ... your stuff ...
1263// }
1264// EX_END_HOOK
1265// ... control will never get here ...
1266//
1267//
1268// EX_HOOK is like EX_CATCH except that you can't prevent the
1269// exception from being rethrown. You can throw a new exception inside the hook
1270// (for example, if you want to wrap the exception in flight with your own).
1271// But if control reaches the end of the hook, the original exception gets rethrown.
1272//
1273// Avoid using EX_HOOK for conditional backout if a destructor-based holder
1274// will suffice. Because these macros are implemented on top of SEH, using them will
1275// prevent the use of holders anywhere else inside the same function. That is, instead
1276// of saying this:
1277//
1278// EX_TRY // DON'T DO THIS
1279// {
1280// thing = new Thing();
1281// blah
1282// }
1283// EX_HOOK
1284// {
1285// delete thing; // if it failed, we don't want to keep the Thing.
1286// }
1287// EX_END_HOOK
1288//
1289// do this:
1290//
1291// Holder<Thing> thing = new Thing(); //DO THIS INSTEAD
1292// blah
1293// // If we got here, we succeeded. So tell holder we want to keep the thing.
1294// thing.SuppressRelease();
1295//
1296// We won't rethrow the exception if it is a Stack Overflow exception. Instead, we'll throw a new
1297// exception. This will allow the stack to unwind point, and so we won't be jeopardizing a
1298// second stack overflow.
1299//===================================================================================
1300#define EX_HOOK \
1301 EX_CATCH \
1302 { \
1303
1304#define EX_END_HOOK \
1305 } \
1306 ANNOTATION_HANDLER_END; \
1307 if (IsCurrentExceptionSO()) \
1308 __state.SetCaughtSO(); \
1309 VM_NO_SO_INFRASTRUCTURE_CODE(_ASSERTE(!__state.DidCatchSO());) \
1310 if (!__state.DidCatchSO()) \
1311 EX_RETHROW; \
1312 EX_END_CATCH_FOR_HOOK; \
1313 SO_INFRASTRUCTURE_CODE(if (__state.DidCatchSO())) \
1314 SO_INFRASTRUCTURE_CODE(ThrowStackOverflow();) \
1315 } \
1316
1317// ---------------------------------------------------------------------------
1318// Inline implementations. Pay no attention to that man behind the curtain.
1319// ---------------------------------------------------------------------------
1320
1321inline Exception::HandlerState::HandlerState()
1322{
1323 STATIC_CONTRACT_NOTHROW;
1324 STATIC_CONTRACT_SO_TOLERANT;
1325 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
1326 STATIC_CONTRACT_SUPPORTS_DAC;
1327
1328 m_dwFlags = 0;
1329 m_pExceptionPtr = NULL;
1330
1331#if defined(STACK_GUARDS_DEBUG) && defined(ENABLE_CONTRACTS_IMPL)
1332 // If we have a debug state, use its setting for SO tolerance. The default
1333 // is SO-tolerant if we have no debug state. Can't probe w/o debug state and
1334 // can't enter SO-interolant mode w/o probing.
1335 GetClrDebugState();
1336#endif
1337}
1338
1339inline void Exception::HandlerState::CleanupTry()
1340{
1341 LIMITED_METHOD_DAC_CONTRACT;
1342}
1343
1344inline void Exception::HandlerState::SetupCatch(INDEBUG_COMMA(__in_z const char * szFile) int lineNum, bool fVMInitialized /* = true */)
1345{
1346 WRAPPER_NO_CONTRACT;
1347
1348 if (fVMInitialized)
1349 {
1350 // Calling into IsCurrentExceptionSO will end up using various VM support entities (e.g. TLS slots, accessing CExecutionEngine
1351 // implementation that accesses other VM specific data, etc) that may not be ready/initialized
1352 // until the VM is initialized.
1353 //
1354 // This is particularly important when we have exceptions thrown/triggerred during runtime's initialization
1355 // and accessing such data can result in possible recursive AV's in the runtime.
1356 if (IsCurrentExceptionSO())
1357 SetCaughtSO();
1358 }
1359
1360 /* don't embed file names in retail to save space and avoid IP */
1361 /* a findstr /n will allow you to locate it in a pinch */
1362#ifdef _DEBUG
1363 STRESS_LOG2(LF_EH, LL_INFO100, "EX_CATCH %s line %d\n", szFile, lineNum);
1364#else
1365 STRESS_LOG1(LF_EH, LL_INFO100, "EX_CATCH line %d\n", lineNum);
1366#endif
1367
1368 SetCaught();
1369}
1370
1371inline void Exception::HandlerState::SucceedCatch()
1372{
1373 LIMITED_METHOD_DAC_CONTRACT;
1374}
1375
1376inline HRException::HRException()
1377 : m_hr(E_UNEXPECTED)
1378{
1379 LIMITED_METHOD_CONTRACT;
1380 SUPPORTS_DAC;
1381}
1382
1383inline HRException::HRException(HRESULT hr)
1384 : m_hr(hr)
1385{
1386 LIMITED_METHOD_CONTRACT;
1387 SUPPORTS_DAC;
1388
1389 // Catchers assume only failing hresults
1390 _ASSERTE(FAILED(hr));
1391}
1392
1393inline HRMsgException::HRMsgException()
1394 : HRException()
1395{
1396 LIMITED_METHOD_CONTRACT;
1397}
1398
1399inline HRMsgException::HRMsgException(HRESULT hr, SString const &s)
1400 : HRException(hr), m_msg(s)
1401{
1402 WRAPPER_NO_CONTRACT;
1403}
1404
1405inline COMException::COMException()
1406 : HRException(),
1407 m_pErrorInfo(NULL)
1408{
1409 WRAPPER_NO_CONTRACT;
1410}
1411
1412inline COMException::COMException(HRESULT hr)
1413 : HRException(hr),
1414 m_pErrorInfo(NULL)
1415{
1416 LIMITED_METHOD_CONTRACT;
1417}
1418
1419inline COMException::COMException(HRESULT hr, IErrorInfo *pErrorInfo)
1420 : HRException(hr),
1421 m_pErrorInfo(pErrorInfo)
1422{
1423 LIMITED_METHOD_CONTRACT;
1424}
1425
1426inline SEHException::SEHException()
1427{
1428 LIMITED_METHOD_CONTRACT;
1429 memset(&m_exception, 0, sizeof(EXCEPTION_RECORD));
1430}
1431
1432inline SEHException::SEHException(EXCEPTION_RECORD *pointers, T_CONTEXT *pContext)
1433{
1434 LIMITED_METHOD_CONTRACT;
1435 memcpy(&m_exception, pointers, sizeof(EXCEPTION_RECORD));
1436}
1437
1438// The exception throwing helpers are intentionally not inlined
1439// Exception throwing is a rare slow codepath that should be optimized for code size
1440
1441void DECLSPEC_NORETURN ThrowHR(HRESULT hr);
1442void DECLSPEC_NORETURN ThrowHR(HRESULT hr, SString const &msg);
1443void DECLSPEC_NORETURN ThrowHR(HRESULT hr, UINT uText);
1444void DECLSPEC_NORETURN ThrowWin32(DWORD err);
1445void DECLSPEC_NORETURN ThrowLastError();
1446void DECLSPEC_NORETURN ThrowOutOfMemory();
1447void DECLSPEC_NORETURN ThrowStackOverflow();
1448void DECLSPEC_NORETURN ThrowMessage(LPCSTR message, ...);
1449
1450#undef IfFailThrow
1451inline HRESULT IfFailThrow(HRESULT hr)
1452{
1453 WRAPPER_NO_CONTRACT;
1454
1455 if (FAILED(hr))
1456 {
1457 ThrowHR(hr);
1458 }
1459
1460 return hr;
1461}
1462
1463inline HRESULT IfFailThrow(HRESULT hr, SString &msg)
1464{
1465 WRAPPER_NO_CONTRACT;
1466
1467 if (FAILED(hr))
1468 {
1469 ThrowHR(hr, msg);
1470 }
1471
1472 return hr;
1473}
1474
1475inline HRESULT IfTransientFailThrow(HRESULT hr)
1476{
1477 WRAPPER_NO_CONTRACT;
1478
1479 if (FAILED(hr) && Exception::IsTransient(hr))
1480 {
1481 ThrowHR(hr);
1482 }
1483
1484 return hr;
1485}
1486
1487// Set if fatal error (like stack overflow or out of memory) occurred in this process.
1488GVAL_DECL(HRESULT, g_hrFatalError);
1489
1490#endif // _EX_H_
1491