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.
7 // ---------------------------------------------------------------------------
9 // ---------------------------------------------------------------------------
15 #include "eetoprofinterfacewrapper.inl"
16 #include "typestring.h"
17 #include "sigformat.h"
19 #include "frameworkexceptionloader.h"
21 #ifdef WIN64EXCEPTIONS
22 #include "exceptionhandling.h"
23 #endif // WIN64EXCEPTIONS
25 #ifdef FEATURE_COMINTEROP
26 #include "interoputil.inl"
27 #endif // FEATURE_COMINTEROP
29 // ---------------------------------------------------------------------------
30 // CLRException methods
31 // ---------------------------------------------------------------------------
33 CLRException::~CLRException()
40 if (GetThrowableHandle() == NULL)
46 CAN_TAKE_LOCK; // because of DestroyHandle
51 #ifndef CROSSGEN_COMPILE
52 OBJECTHANDLE throwableHandle = GetThrowableHandle();
53 if (throwableHandle != NULL)
55 STRESS_LOG1(LF_EH, LL_INFO100, "CLRException::~CLRException destroying throwable: obj = %x\n", GetThrowableHandle());
56 // clear the handle first, so if we SO on destroying it, we don't have a dangling reference
57 SetThrowableHandle(NULL);
58 DestroyHandle(throwableHandle);
63 OBJECTREF CLRException::GetThrowable()
74 #ifdef CROSSGEN_COMPILE
78 OBJECTREF throwable = NULL;
85 Thread *pThread = GetThread();
87 if (pThread->IsRudeAbortInitiated()) {
88 return GetPreallocatedRudeThreadAbortException();
91 if ((IsType(CLRLastThrownObjectException::GetType()) &&
92 pThread->LastThrownObject() == GetPreallocatedStackOverflowException()))
94 return GetPreallocatedStackOverflowException();
97 OBJECTHANDLE oh = GetThrowableHandle();
100 return ObjectFromHandle(oh);
103 Exception *pLastException = pThread->m_pCreatingThrowableForException;
104 if (pLastException != NULL)
106 if (IsSameInstanceType(pLastException))
109 static int BreakOnExceptionInGetThrowable = -1;
110 if (BreakOnExceptionInGetThrowable == -1)
112 BreakOnExceptionInGetThrowable = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnExceptionInGetThrowable);
114 if (BreakOnExceptionInGetThrowable)
116 _ASSERTE(!"BreakOnExceptionInGetThrowable");
118 LOG((LF_EH, LL_INFO100, "GetThrowable: Exception in GetThrowable, translating to a preallocated exception.\n"));
120 // Look at the type of GET_EXCEPTION() and see if it is OOM or SO.
121 if (IsPreallocatedOOMException())
123 throwable = GetPreallocatedOutOfMemoryException();
125 else if (GetInstanceType() == EEException::GetType() && GetHR() == COR_E_THREADABORTED)
127 // If creating a normal ThreadAbortException fails, due to OOM or StackOverflow,
128 // use a pre-created one.
129 // We do not won't to change a ThreadAbortException into OOM or StackOverflow, because
130 // it will cause recursive call when escalation policy is on:
131 // Creating ThreadAbortException fails, we throw OOM. Escalation leads to ThreadAbort.
132 // The cycle repeats.
133 throwable = GetPreallocatedThreadAbortException();
137 // I am not convinced if this case is actually a fatal error in the runtime.
138 // There have been two bugs in early 2006 (VSW 575647 and 575650) that came in here,
139 // both because of OOM and resulted in the ThreadAbort clause above being added since
140 // we were creating a ThreadAbort throwable that, due to OOM, got us on a path
141 // which came here. Both were valid execution paths and scenarios and not a fatal condition.
143 // I am tempted to return preallocated OOM from here but my concern is that it *may*
144 // result in fake OOM exceptions being thrown that could break valid scenarios.
146 // Hence, we return preallocated System.Exception instance. Lossy information is better
147 // than wrong or no information (or even FailFast).
148 _ASSERTE (!"Recursion in CLRException::GetThrowable");
150 // We didn't recognize it, so use the preallocated System.Exception instance.
151 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowable: Recursion! Translating to preallocated System.Exception.\n");
152 throwable = GetPreallocatedBaseException();
157 GCPROTECT_BEGIN(throwable);
159 if (throwable == NULL)
161 class RestoreLastException
164 Exception *m_pLastException;
166 RestoreLastException(Thread *pThread, Exception *pException)
169 m_pLastException = m_pThread->m_pCreatingThrowableForException;
170 m_pThread->m_pCreatingThrowableForException = pException;
172 ~RestoreLastException()
174 m_pThread->m_pCreatingThrowableForException = m_pLastException;
178 RestoreLastException restore(pThread, this);
183 throwable = CreateThrowable();
187 // This code used to be this line:
188 // throwable = GET_THROWABLE();
189 // GET_THROWABLE() expands to CLRException::GetThrowable(GET_EXCEPTION()),
190 // (where GET_EXCEPTION() refers to the exception that was thrown from
191 // CreateThrowable() and is being caught in this EX_TRY/EX_CATCH.)
192 // If that exception is the same as the one for which this GetThrowable()
193 // was called, we're in a recursive situation.
194 // Since the CreateThrowable() call should return a type from mscorlib,
195 // there really shouldn't be much opportunity for error. We could be
196 // out of memory, we could overflow the stack, or the runtime could
197 // be in a weird state(the thread could be aborted as well).
198 // Because we've seen a number of recursive death bugs here, just look
199 // explicitly for OOM and SO, and otherwise use ExecutionEngineException.
201 // Check whether the exception from CreateThrowable() is the same as the current
202 // exception. If not, call GetThrowable(), otherwise, settle for a
203 // preallocated exception.
204 Exception *pException = GET_EXCEPTION();
206 if (GetHR() == COR_E_THREADABORTED)
208 // If creating a normal ThreadAbortException fails, due to OOM or StackOverflow,
209 // use a pre-created one.
210 // We do not won't to change a ThreadAbortException into OOM or StackOverflow, because
211 // it will cause recursive call when escalation policy is on:
212 // Creating ThreadAbortException fails, we throw OOM. Escalation leads to ThreadAbort.
213 // The cycle repeats.
214 throwable = GetPreallocatedThreadAbortException();
218 throwable = CLRException::GetThrowableFromException(pException);
221 EX_END_CATCH(SwallowAllExceptions)
226 if (throwable == NULL)
228 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowable: We have failed to track exceptions accurately through the system.\n");
230 // There's no reason to believe that it is an OOM. A better choice is ExecutionEngineException.
231 // We have failed to track exceptions accurately through the system. However, it's arguably
232 // better to give the wrong exception object than it is to rip the process. So let's leave
233 // it as an Assert for now and convert it to ExecutionEngineException in the next release.
235 // SQL Stress is hitting the assert. We want to remove it, so that we can see if there are further errors
236 // masked by the assert.
239 throwable = GetPreallocatedOutOfMemoryException();
244 SetThrowableHandle(GetAppDomain()->CreateHandle(throwable));
245 if (m_innerException != NULL && !CLRException::IsPreallocatedExceptionObject(throwable))
247 // Only set inner exception if the exception is not preallocated.
250 // If inner exception is not empty, then set the managed exception's
251 // _innerException field properly
252 OBJECTREF throwableValue = CLRException::GetThrowableFromException(m_innerException);
253 ((EXCEPTIONREF)throwable)->SetInnerException(throwableValue);
259 // No matter... we just don't get to cache the throwable.
261 EX_END_CATCH(SwallowAllExceptions)
270 HRESULT CLRException::GetHR()
281 return GetExceptionHResult(GetThrowable());
284 #ifdef FEATURE_COMINTEROP
285 HRESULT CLRException::SetErrorInfo()
297 IErrorInfo *pErrorInfo = NULL;
299 // Try to get IErrorInfo
302 pErrorInfo = GetErrorInfo();
306 // Since there was an exception getting IErrorInfo get the exception's HR so
307 // that we return it back to the caller as the new exception.
308 hr = GET_EXCEPTION()->GetHR();
310 LOG((LF_EH, LL_INFO100, "CLRException::SetErrorInfo: caught exception (hr = %08X) while trying to get IErrorInfo\n", hr));
312 EX_END_CATCH(SwallowAllExceptions)
316 // Return the HR to the caller if we dont get IErrorInfo - if the HR is E_NOINTERFACE, then
317 // there was no IErrorInfo available. If its anything else, it implies we failed to get the
318 // interface and have the HR corresponding to the exception we took while trying to get IErrorInfo.
327 ::SetErrorInfo(0, pErrorInfo);
328 pErrorInfo->Release();
330 // Success in setting the ErrorInfo on the thread
335 hr = GET_EXCEPTION()->GetHR();
337 LOG((LF_EH, LL_INFO100, "CLRException::SetErrorInfo: caught exception (hr = %08X) while trying to set IErrorInfo\n", hr));
339 EX_END_CATCH(SwallowAllExceptions)
345 IErrorInfo *CLRException::GetErrorInfo()
355 IErrorInfo *pErrorInfo = NULL;
357 #ifndef CROSSGEN_COMPILE
358 // Attempt to get IErrorInfo only if COM is initialized.
359 // Not all codepaths expect to have it initialized (e.g. hosting APIs).
362 // Get errorinfo only when our SO probe succeeds
364 // Switch to coop mode since GetComIPFromObjectRef requires that
365 // and we could be here in any mode...
375 pErrorInfo = (IErrorInfo *)GetComIPFromObjectRef(&e, IID_IErrorInfo);
383 // Write to the log incase COM isnt initialized.
384 LOG((LF_EH, LL_INFO100, "CLRException::GetErrorInfo: exiting since COM is not initialized.\n"));
386 #endif //CROSSGEN_COMPILE
388 // return the IErrorInfo we got...
391 #else // FEATURE_COMINTEROP
392 IErrorInfo *CLRException::GetErrorInfo()
394 LIMITED_METHOD_CONTRACT;
397 HRESULT CLRException::SetErrorInfo()
399 LIMITED_METHOD_CONTRACT;
403 #endif // FEATURE_COMINTEROP
405 void CLRException::GetMessage(SString &result)
415 #ifndef CROSSGEN_COMPILE
418 OBJECTREF e = GetThrowable();
421 _ASSERTE(IsException(e->GetMethodTable()));
425 STRINGREF message = ((EXCEPTIONREF)e)->GetMessage();
430 message->GetSString(result);
437 #ifndef CROSSGEN_COMPILE
438 OBJECTREF CLRException::GetPreallocatedBaseException()
441 _ASSERTE(g_pPreallocatedBaseException != NULL);
442 return ObjectFromHandle(g_pPreallocatedBaseException);
445 OBJECTREF CLRException::GetPreallocatedOutOfMemoryException()
448 _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
449 return ObjectFromHandle(g_pPreallocatedOutOfMemoryException);
452 OBJECTREF CLRException::GetPreallocatedStackOverflowException()
455 _ASSERTE(g_pPreallocatedStackOverflowException != NULL);
456 return ObjectFromHandle(g_pPreallocatedStackOverflowException);
459 OBJECTREF CLRException::GetPreallocatedExecutionEngineException()
462 _ASSERTE(g_pPreallocatedExecutionEngineException != NULL);
463 return ObjectFromHandle(g_pPreallocatedExecutionEngineException);
466 OBJECTREF CLRException::GetPreallocatedRudeThreadAbortException()
469 // When we are hosted, we pre-create this exception.
470 // This function should be called only if the exception has been created.
471 _ASSERTE(g_pPreallocatedRudeThreadAbortException);
472 return ObjectFromHandle(g_pPreallocatedRudeThreadAbortException);
475 OBJECTREF CLRException::GetPreallocatedThreadAbortException()
478 _ASSERTE(g_pPreallocatedThreadAbortException);
479 return ObjectFromHandle(g_pPreallocatedThreadAbortException);
482 OBJECTHANDLE CLRException::GetPreallocatedOutOfMemoryExceptionHandle()
484 LIMITED_METHOD_CONTRACT;
485 _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
486 return g_pPreallocatedOutOfMemoryException;
489 OBJECTHANDLE CLRException::GetPreallocatedThreadAbortExceptionHandle()
491 LIMITED_METHOD_CONTRACT;
492 _ASSERTE(g_pPreallocatedThreadAbortException != NULL);
493 return g_pPreallocatedThreadAbortException;
496 OBJECTHANDLE CLRException::GetPreallocatedRudeThreadAbortExceptionHandle()
498 LIMITED_METHOD_CONTRACT;
499 _ASSERTE(g_pPreallocatedRudeThreadAbortException != NULL);
500 return g_pPreallocatedRudeThreadAbortException;
503 OBJECTHANDLE CLRException::GetPreallocatedStackOverflowExceptionHandle()
505 LIMITED_METHOD_CONTRACT;
506 _ASSERTE(g_pPreallocatedStackOverflowException != NULL);
507 return g_pPreallocatedStackOverflowException;
510 OBJECTHANDLE CLRException::GetPreallocatedExecutionEngineExceptionHandle()
512 LIMITED_METHOD_CONTRACT;
513 _ASSERTE(g_pPreallocatedExecutionEngineException != NULL);
514 return g_pPreallocatedExecutionEngineException;
518 // Returns TRUE if the given object ref is one of the preallocated exception objects.
520 BOOL CLRException::IsPreallocatedExceptionObject(OBJECTREF o)
531 if ((o == ObjectFromHandle(g_pPreallocatedBaseException)) ||
532 (o == ObjectFromHandle(g_pPreallocatedOutOfMemoryException)) ||
533 (o == ObjectFromHandle(g_pPreallocatedStackOverflowException)) ||
534 (o == ObjectFromHandle(g_pPreallocatedExecutionEngineException)))
539 // The preallocated rude thread abort exception is not always preallocated.
540 if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
541 (o == ObjectFromHandle(g_pPreallocatedRudeThreadAbortException)))
546 // The preallocated rude thread abort exception is not always preallocated.
547 if ((g_pPreallocatedThreadAbortException != NULL) &&
548 (o == ObjectFromHandle(g_pPreallocatedThreadAbortException)))
557 // Returns TRUE if the given object ref is one of the preallocated exception handles
559 BOOL CLRException::IsPreallocatedExceptionHandle(OBJECTHANDLE h)
570 if ((h == g_pPreallocatedBaseException) ||
571 (h == g_pPreallocatedOutOfMemoryException) ||
572 (h == g_pPreallocatedStackOverflowException) ||
573 (h == g_pPreallocatedExecutionEngineException) ||
574 (h == g_pPreallocatedThreadAbortException))
579 // The preallocated rude thread abort exception is not always preallocated.
580 if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
581 (h == g_pPreallocatedRudeThreadAbortException))
590 // Returns a preallocated handle to match a preallocated exception object, or NULL if the object isn't one of the
591 // preallocated exception objects.
593 OBJECTHANDLE CLRException::GetPreallocatedHandleForObject(OBJECTREF o)
604 if (o == ObjectFromHandle(g_pPreallocatedBaseException))
606 return g_pPreallocatedBaseException;
608 else if (o == ObjectFromHandle(g_pPreallocatedOutOfMemoryException))
610 return g_pPreallocatedOutOfMemoryException;
612 else if (o == ObjectFromHandle(g_pPreallocatedStackOverflowException))
614 return g_pPreallocatedStackOverflowException;
616 else if (o == ObjectFromHandle(g_pPreallocatedExecutionEngineException))
618 return g_pPreallocatedExecutionEngineException;
620 else if (o == ObjectFromHandle(g_pPreallocatedThreadAbortException))
622 return g_pPreallocatedThreadAbortException;
625 // The preallocated rude thread abort exception is not always preallocated.
626 if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
627 (o == ObjectFromHandle(g_pPreallocatedRudeThreadAbortException)))
629 return g_pPreallocatedRudeThreadAbortException;
635 // Prefer a new OOM exception if we can make one. If we cannot, then give back the pre-allocated one.
636 OBJECTREF CLRException::GetBestOutOfMemoryException()
645 OBJECTREF retVal = NULL;
651 EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
652 pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
653 pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
655 retVal = pOutOfMemory;
659 retVal = GetPreallocatedOutOfMemoryException();
661 EX_END_CATCH(SwallowAllExceptions)
663 _ASSERTE(retVal != NULL);
669 // Works on non-CLRExceptions as well
671 OBJECTREF CLRException::GetThrowableFromException(Exception *pException)
681 Thread* pThread = GetThread();
683 // Can't have a throwable without a Thread.
684 _ASSERTE(pThread != NULL);
686 if (NULL == pException)
688 return pThread->LastThrownObject();
691 if (pException->IsType(CLRException::GetType()))
692 return ((CLRException*)pException)->GetThrowable();
694 if (pException->IsType(EEException::GetType()))
695 return ((EEException*)pException)->GetThrowable();
697 // Note: we are creating a throwable on the fly in this case - so
698 // multiple calls will return different objects. If we really need identity,
699 // we could store a throwable handle at the catch site, or store it
700 // on the thread object.
702 if (pException->IsType(SEHException::GetType()))
704 SEHException *pSEHException = (SEHException*)pException;
706 switch (pSEHException->m_exception.ExceptionCode)
708 case EXCEPTION_COMPLUS:
709 // Note: even though the switch compared the exception code,
710 // we have to call the official IsComPlusException() routine
711 // for side-by-side correctness. If that check fails, treat
712 // as an unrelated unmanaged exception.
713 if (IsComPlusException(&(pSEHException->m_exception)))
715 return pThread->LastThrownObject();
722 case STATUS_NO_MEMORY:
723 return GetBestOutOfMemoryException();
725 case STATUS_STACK_OVERFLOW:
726 return GetPreallocatedStackOverflowException();
729 DWORD exceptionCode =
730 MapWin32FaultToCOMPlusException(&pSEHException->m_exception);
732 EEException e((RuntimeExceptionKind)exceptionCode);
734 OBJECTREF throwable = e.GetThrowable();
735 GCPROTECT_BEGIN (throwable);
739 if (throwable != NULL && !CLRException::IsPreallocatedExceptionObject(throwable))
741 _ASSERTE(IsException(throwable->GetMethodTable()));
743 // set the exception code
744 ((EXCEPTIONREF)throwable)->SetXCode(pSEHException->m_exception.ExceptionCode);
750 EX_END_CATCH(SwallowAllExceptions)
757 // We can enter here for HRException, COMException, DelegatingException
758 // just to name a few.
759 OBJECTREF oRetVal = NULL;
760 GCPROTECT_BEGIN(oRetVal);
764 HRESULT hr = pException->GetHR();
766 if (hr == E_OUTOFMEMORY || hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY))
768 oRetVal = GetBestOutOfMemoryException();
770 else if (hr == COR_E_STACKOVERFLOW)
772 oRetVal = GetPreallocatedStackOverflowException();
776 SafeComHolder<IErrorInfo> pErrInfo(pException->GetErrorInfo());
778 if (pErrInfo != NULL)
780 GetExceptionForHR(hr, pErrInfo, &oRetVal);
785 pException->GetMessage(message);
787 EEMessageException e(hr, IDS_EE_GENERIC, message);
789 oRetVal = e.CreateThrowable();
795 // We have caught an exception trying to get a Throwable for the pException we
796 // were given. It is tempting to want to get the Throwable for the new
797 // exception, but that is dangerous, due to infinitely cascading
798 // exceptions, leading to a stack overflow.
800 // If we can see that the exception was OOM, return the preallocated OOM,
801 // if we can see that it is SO, return the preallocated SO,
802 // if we can see that it is some other managed exception, return that
803 // exception, otherwise return the preallocated System.Exception.
804 Exception *pNewException = GET_EXCEPTION();
806 if (pNewException->IsPreallocatedOOMException())
807 { // It definitely was an OOM
808 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: OOM creating throwable; getting pre-alloc'd OOM.\n");
810 oRetVal = GetPreallocatedOutOfMemoryException();
813 if (pNewException->IsType(CLRLastThrownObjectException::GetType()) &&
814 (pThread->LastThrownObject() != NULL))
816 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: LTO Exception creating throwable; getting LastThrownObject.\n");
818 oRetVal = pThread->LastThrownObject();
822 // We *could* come here if one of the calls in the EX_TRY above throws an exception (e.g. MissingMethodException if we attempt
823 // to invoke CreateThrowable for a type that does not have a default constructor) that is neither preallocated OOM nor a
824 // CLRLastThrownObject type.
826 // Like the comment says above, we cannot afford to get the throwable lest we hit SO. In such a case, runtime is not in a bad shape
827 // but we dont know what to return as well. A reasonable answer is to return something less appropriate than ripping down process
828 // or returning an incorrect exception (e.g. OOM) that could break execution paths.
830 // Hence, we return preallocated System.Exception instance.
833 oRetVal = GetPreallocatedBaseException();
834 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: Unknown Exception creating throwable; getting preallocated System.Exception.\n");
839 EX_END_CATCH(SwallowAllExceptions)
845 } // OBJECTREF CLRException::GetThrowableFromException()
847 OBJECTREF CLRException::GetThrowableFromExceptionRecord(EXCEPTION_RECORD *pExceptionRecord)
857 if (IsComPlusException(pExceptionRecord))
859 return GetThread()->LastThrownObject();
865 void CLRException::HandlerState::CleanupTry()
867 STATIC_CONTRACT_NOTHROW;
868 STATIC_CONTRACT_GC_NOTRIGGER;
869 STATIC_CONTRACT_MODE_ANY;
871 if (m_pThread != NULL)
873 BEGIN_GETTHREAD_ALLOWED;
874 // If there is no frame to unwind, UnwindFrameChain call is just an expensive NOP
875 // due to setting up and tear down of EH records. So we avoid it if we can.
876 if (m_pThread->GetFrame() < m_pFrame)
877 UnwindFrameChain(m_pThread, m_pFrame);
879 if (m_fPreemptiveGCDisabled != m_pThread->PreemptiveGCDisabled())
881 if (m_fPreemptiveGCDisabled)
882 m_pThread->DisablePreemptiveGC();
884 m_pThread->EnablePreemptiveGC();
886 END_GETTHREAD_ALLOWED;
889 // Make sure to call the base class's CleanupTry so it can do whatever it wants to do.
890 Exception::HandlerState::CleanupTry();
893 void CLRException::HandlerState::SetupCatch(INDEBUG_COMMA(__in_z const char * szFile) int lineNum)
895 STATIC_CONTRACT_NOTHROW;
896 STATIC_CONTRACT_GC_NOTRIGGER;
897 STATIC_CONTRACT_MODE_ANY;
898 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
900 Exception::HandlerState::SetupCatch(INDEBUG_COMMA(szFile) lineNum);
902 Thread *pThread = NULL;
903 DWORD exceptionCode = 0;
907 pThread = GetThread();
908 exceptionCode = GetCurrentExceptionCode();
913 if (exceptionCode == STATUS_STACK_OVERFLOW)
915 // Handle SO exception
917 // We should ensure that a valid Thread object exists before trying to set SO as the LTO.
920 // We have a nasty issue with our EX_TRY/EX_CATCH. If EX_CATCH catches SEH exception,
921 // GET_THROWABLE uses CLRLastThrownObjectException instead, because we don't know
922 // what exception to use. But for SO, we can use preallocated SO exception.
924 pThread->SetSOForLastThrownObject();
927 if (exceptionCode == STATUS_STACK_OVERFLOW)
929 // We have called HandleStackOverflow for soft SO through our vectored exception handler.
930 EEPolicy::HandleStackOverflow(SOD_UnmanagedFrameHandler, FRAME_TOP);
935 #ifdef WIN64EXCEPTIONS
938 // this must be done after the second pass has run, it does not
939 // reference anything on the stack, so it is safe to run in an
940 // SEH __except clause as well as a C++ catch clause.
941 ExceptionTracker::PopTrackers(this);
943 #endif // WIN64EXCEPTIONS
947 void CLRException::HandlerState::SucceedCatch()
949 STATIC_CONTRACT_NOTHROW;
950 STATIC_CONTRACT_GC_NOTRIGGER;
951 STATIC_CONTRACT_MODE_ANY;
952 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
954 LOG((LF_EH, LL_INFO100, "EX_CATCH catch succeeded (CLRException::HandlerState)\n"));
957 // At this point, we don't believe we need to do any unwinding of the ExInfo chain after an EX_CATCH. The chain
958 // is unwound by CPFH_UnwindFrames1() when it detects that the exception is being caught by an unmanaged
959 // catcher. EX_CATCH looks just like an unmanaged catcher now, so the unwind is already done by the time we get
960 // into the catch. That's different than before the big switch to the new exeption system, and it effects
961 // rethrows. Fixing rethrows is a work item for a little later. For now, we're simplying removing the unwind
962 // from here to avoid the extra unwind, which is harmless in many cases, but is very harmful when a managed
963 // filter throws an exception.
967 Exception::HandlerState::SucceedCatch();
971 #endif // CROSSGEN_COMPILE
973 // ---------------------------------------------------------------------------
974 // EEException methods
975 // ---------------------------------------------------------------------------
977 //------------------------------------------------------------------------
978 // Array that is used to retrieve the right exception for a given HRESULT.
979 //------------------------------------------------------------------------
981 #ifdef FEATURE_COMINTEROP
983 struct WinRtHR_to_ExceptionKind_Map
985 RuntimeExceptionKind reKind;
990 enum WinRtOnly_ExceptionKind {
991 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) kWinRtEx##reKind,
992 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...)
993 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...)
995 kWinRtExLastException
998 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) static const HRESULT s_##reKind##WinRtOnlyHRs[] = { __VA_ARGS__ };
999 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...)
1000 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...)
1004 WinRtHR_to_ExceptionKind_Map gWinRtHR_to_ExceptionKind_Maps[] = {
1005 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) { k##reKind, sizeof(s_##reKind##WinRtOnlyHRs) / sizeof(HRESULT), s_##reKind##WinRtOnlyHRs },
1006 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...)
1007 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...)
1011 #endif // FEATURE_COMINTEROP
1013 struct ExceptionHRInfo
1016 const HRESULT *aHRs;
1019 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) static const HRESULT s_##reKind##HRs[] = { __VA_ARGS__ };
1020 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
1021 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
1025 ExceptionHRInfo gExceptionHRInfos[] = {
1026 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) {sizeof(s_##reKind##HRs) / sizeof(HRESULT), s_##reKind##HRs},
1027 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
1028 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
1034 bool gShouldDisplayHR[] =
1036 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) bHRformessage,
1037 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
1038 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
1044 HRESULT EEException::GetHRFromKind(RuntimeExceptionKind reKind)
1046 LIMITED_METHOD_CONTRACT;
1047 return gExceptionHRInfos[reKind].aHRs[0];
1050 HRESULT EEException::GetHR()
1052 LIMITED_METHOD_CONTRACT;
1054 return EEException::GetHRFromKind(m_kind);
1057 IErrorInfo *EEException::GetErrorInfo()
1059 LIMITED_METHOD_CONTRACT;
1064 BOOL EEException::GetThrowableMessage(SString &result)
1074 // Return a meaningful HR message, if there is one.
1076 HRESULT hr = GetHR();
1078 // If the hr is more interesting than the kind, use that
1083 && (gShouldDisplayHR[m_kind]
1084 || gExceptionHRInfos[m_kind].aHRs[0] != hr))
1086 // If it has only one HR, the original message should be good enough
1087 _ASSERTE(gExceptionHRInfos[m_kind].cHRs > 1 ||
1088 gExceptionHRInfos[m_kind].aHRs[0] != hr);
1090 GenerateTopLevelHRExceptionMessage(hr, result);
1094 // No interesting hr - just keep the class default message.
1099 void EEException::GetMessage(SString &result)
1109 // First look for a specialized message
1110 if (GetThrowableMessage(result))
1113 // Otherwise, report the class's generic message
1114 LPCUTF8 pszExceptionName = NULL;
1115 if (m_kind <= kLastExceptionInMscorlib)
1117 pszExceptionName = MscorlibBinder::GetExceptionName(m_kind);
1118 result.SetUTF8(pszExceptionName);
1120 #ifndef CROSSGEN_COMPILE
1123 FrameworkExceptionLoader::GetExceptionName(m_kind, result);
1125 #endif // CROSSGEN_COMPILE
1128 OBJECTREF EEException::CreateThrowable()
1130 #ifdef CROSSGEN_COMPILE
1142 _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
1143 static int allocCount = 0;
1145 MethodTable *pMT = NULL;
1146 if (m_kind <= kLastExceptionInMscorlib)
1147 pMT = MscorlibBinder::GetException(m_kind);
1150 pMT = FrameworkExceptionLoader::GetException(m_kind);
1153 ThreadPreventAsyncHolder preventAsyncHolder(m_kind == kThreadAbortException);
1155 OBJECTREF throwable = AllocateObject(pMT);
1157 GCPROTECT_BEGIN(throwable);
1160 ThreadPreventAsyncHolder preventAbort(m_kind == kThreadAbortException ||
1161 m_kind == kThreadInterruptedException);
1162 CallDefaultConstructor(throwable);
1165 HRESULT hr = GetHR();
1166 ((EXCEPTIONREF)throwable)->SetHResult(hr);
1169 if (GetThrowableMessage(message))
1171 // Set the message field. It is not safe doing this through the constructor
1172 // since the string constructor for some exceptions add a prefix to the message
1173 // which we don't want.
1175 // We only want to replace whatever the default constructor put there, if we
1176 // have something meaningful to add.
1178 STRINGREF s = StringObject::NewString(message);
1179 ((EXCEPTIONREF)throwable)->SetMessage(s);
1188 RuntimeExceptionKind EEException::GetKindFromHR(HRESULT hr, bool fIsWinRtMode /*= false*/)
1190 LIMITED_METHOD_CONTRACT;
1192 #ifdef FEATURE_COMINTEROP
1193 // If we are in WinRT mode, try to get a WinRT specific mapping first:
1196 for (int i = 0; i < kWinRtExLastException; i++)
1198 for (int j = 0; j < gWinRtHR_to_ExceptionKind_Maps[i].cHRs; j++)
1200 if (gWinRtHR_to_ExceptionKind_Maps[i].aHRs[j] == hr)
1202 return gWinRtHR_to_ExceptionKind_Maps[i].reKind;
1207 #endif // FEATURE_COMINTEROP
1209 // Is not in WinRT mode OR did not find a WinRT specific mapping. Check normal mappings:
1211 for (int i = 0; i < kLastException; i++)
1213 for (int j = 0; j < gExceptionHRInfos[i].cHRs; j++)
1215 if (gExceptionHRInfos[i].aHRs[j] == hr)
1216 return (RuntimeExceptionKind) i;
1220 return (fIsWinRtMode ? kException : kCOMException);
1222 } // RuntimeExceptionKind EEException::GetKindFromHR()
1224 BOOL EEException::GetResourceMessage(UINT iResourceID, SString &result,
1225 const SString &arg1, const SString &arg2,
1226 const SString &arg3, const SString &arg4,
1227 const SString &arg5, const SString &arg6)
1240 ok = temp.LoadResource(CCompRC::Error, iResourceID);
1243 result.FormatMessage(FORMAT_MESSAGE_FROM_STRING,
1244 (LPCWSTR)temp, 0, 0, arg1, arg2, arg3, arg4, arg5, arg6);
1249 // ---------------------------------------------------------------------------
1250 // EEMessageException methods
1251 // ---------------------------------------------------------------------------
1253 HRESULT EEMessageException::GetHR()
1255 WRAPPER_NO_CONTRACT;
1260 BOOL EEMessageException::GetThrowableMessage(SString &result)
1270 if (m_resID != 0 && GetResourceMessage(m_resID, result))
1273 return EEException::GetThrowableMessage(result);
1276 BOOL EEMessageException::GetResourceMessage(UINT iResourceID, SString &result)
1278 WRAPPER_NO_CONTRACT;
1280 return EEException::GetResourceMessage(
1281 iResourceID, result, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6);
1284 // ---------------------------------------------------------------------------
1285 // EEResourceException methods
1286 // ---------------------------------------------------------------------------
1288 void EEResourceException::GetMessage(SString &result)
1290 WRAPPER_NO_CONTRACT;
1292 // Return a simplified message,
1293 // since we don't want to call managed code here.
1296 result.Printf("%s (message resource %s)",
1297 MscorlibBinder::GetExceptionName(m_kind), m_resourceName.GetUnicode());
1300 BOOL EEResourceException::GetThrowableMessage(SString &result)
1310 #ifndef CROSSGEN_COMPILE
1311 STRINGREF message = NULL;
1312 ResMgrGetString(m_resourceName, &message);
1314 if (message != NULL)
1316 message->GetSString(result);
1319 #endif // CROSSGEN_COMPILE
1321 return EEException::GetThrowableMessage(result);
1324 // ---------------------------------------------------------------------------
1325 // EEFieldException is an EE exception subclass composed of a field
1326 // ---------------------------------------------------------------------------
1329 BOOL EEFieldException::GetThrowableMessage(SString &result)
1339 if (m_messageID == 0)
1342 LPCUTF8 szClassName, szMember;
1343 szMember = m_pFD->GetName();
1344 DefineFullyQualifiedNameForClass();
1345 szClassName = GetFullyQualifiedNameForClass(m_pFD->GetApproxEnclosingMethodTable());
1346 MAKE_FULLY_QUALIFIED_MEMBER_NAME(szFullName, NULL, szClassName, szMember, "");
1347 result.SetUTF8(szFullName);
1353 _ASSERTE(m_pAccessingMD != NULL);
1355 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1356 TypeString::FormatNamespace |
1357 TypeString::FormatAngleBrackets |
1358 TypeString::FormatSignature);
1360 StackSString caller;
1361 TypeString::AppendMethod(caller,
1363 m_pAccessingMD->GetClassInstantiation(),
1367 TypeString::AppendField(field,
1369 m_pFD->GetApproxEnclosingMethodTable()->GetInstantiation(),
1372 return GetResourceMessage(m_messageID, result, caller, field, m_additionalContext);
1376 // ---------------------------------------------------------------------------
1377 // EEMethodException is an EE exception subclass composed of a field
1378 // ---------------------------------------------------------------------------
1380 BOOL EEMethodException::GetThrowableMessage(SString &result)
1390 if (m_messageID == 0)
1393 LPCUTF8 szClassName, szMember;
1394 szMember = m_pMD->GetName();
1395 DefineFullyQualifiedNameForClass();
1396 szClassName = GetFullyQualifiedNameForClass(m_pMD->GetMethodTable());
1397 //@todo GENERICS: exact instantiations?
1399 SigFormat sigFormatter(tmp, szMember);
1400 const char * sigStr = sigFormatter.GetCStringParmsOnly();
1401 MAKE_FULLY_QUALIFIED_MEMBER_NAME(szFullName, NULL, szClassName, szMember, sigStr);
1402 result.SetUTF8(szFullName);
1408 _ASSERTE(m_pAccessingMD != NULL);
1410 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1411 TypeString::FormatNamespace |
1412 TypeString::FormatAngleBrackets |
1413 TypeString::FormatSignature);
1415 StackSString caller;
1416 TypeString::AppendMethod(caller,
1418 m_pAccessingMD->GetClassInstantiation(),
1421 StackSString callee;
1422 TypeString::AppendMethod(callee,
1424 m_pMD->GetClassInstantiation(),
1427 return GetResourceMessage(m_messageID, result, caller, callee, m_additionalContext);
1431 BOOL EETypeAccessException::GetThrowableMessage(SString &result)
1441 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1442 TypeString::FormatNamespace |
1443 TypeString::FormatAngleBrackets |
1444 TypeString::FormatSignature);
1446 TypeString::AppendType(type, TypeHandle(m_pMT), formatFlags);
1448 if (m_messageID == 0)
1455 _ASSERTE(m_pAccessingMD != NULL);
1457 StackSString caller;
1458 TypeString::AppendMethod(caller,
1460 m_pAccessingMD->GetClassInstantiation(),
1463 return GetResourceMessage(m_messageID, result, caller, type, m_additionalContext);
1467 // ---------------------------------------------------------------------------
1468 // EEArgumentException is an EE exception subclass representing a bad argument
1469 // ---------------------------------------------------------------------------
1472 OBJECTREF pThrowable;
1474 OBJECTREF pTmpThrowable;
1475 } ProtectArgsStruct;
1477 OBJECTREF EEArgumentException::CreateThrowable()
1479 #ifdef CROSSGEN_COMPILE
1492 _ASSERTE(GetThread() != NULL);
1494 ProtectArgsStruct prot;
1495 memset(&prot, 0, sizeof(ProtectArgsStruct));
1496 ResMgrGetString(m_resourceName, &prot.s1);
1497 GCPROTECT_BEGIN(prot);
1499 MethodTable *pMT = MscorlibBinder::GetException(m_kind);
1500 prot.pThrowable = AllocateObject(pMT);
1502 MethodDesc* pMD = MemberLoader::FindMethod(prot.pThrowable->GetMethodTable(),
1503 COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_RetVoid);
1507 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1508 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1511 MethodDescCallSite exceptionCtor(pMD);
1513 STRINGREF argName = StringObject::NewString(m_argumentName);
1515 // Note that ArgumentException takes arguments to its constructor in a different order,
1516 // for usability reasons. However it is inconsistent with our other exceptions.
1517 if (m_kind == kArgumentException)
1519 ARG_SLOT args1[] = {
1520 ObjToArgSlot(prot.pThrowable),
1521 ObjToArgSlot(prot.s1),
1522 ObjToArgSlot(argName),
1524 exceptionCtor.Call(args1);
1528 ARG_SLOT args1[] = {
1529 ObjToArgSlot(prot.pThrowable),
1530 ObjToArgSlot(argName),
1531 ObjToArgSlot(prot.s1),
1533 exceptionCtor.Call(args1);
1536 GCPROTECT_END(); //Prot
1538 return prot.pThrowable;
1543 // ---------------------------------------------------------------------------
1544 // EETypeLoadException is an EE exception subclass representing a type loading
1546 // ---------------------------------------------------------------------------
1548 EETypeLoadException::EETypeLoadException(LPCUTF8 pszNameSpace, LPCUTF8 pTypeName,
1549 LPCWSTR pAssemblyName, LPCUTF8 pMessageArg, UINT resIDWhy)
1550 : EEException(kTypeLoadException),
1551 m_pAssemblyName(pAssemblyName),
1552 m_pMessageArg(SString::Utf8, pMessageArg),
1553 m_resIDWhy(resIDWhy)
1565 SString sNameSpace(SString::Utf8, pszNameSpace);
1566 SString sTypeName(SString::Utf8, pTypeName);
1567 m_fullName.MakeFullNamespacePath(sNameSpace, sTypeName);
1570 m_fullName.SetUTF8(pTypeName);
1572 WCHAR wszTemplate[30];
1573 if (FAILED(UtilLoadStringRC(IDS_EE_NAME_UNKNOWN,
1575 sizeof(wszTemplate)/sizeof(wszTemplate[0]),
1577 wszTemplate[0] = W('\0');
1578 MAKE_UTF8PTR_FROMWIDE(name, wszTemplate);
1579 m_fullName.SetUTF8(name);
1583 EETypeLoadException::EETypeLoadException(LPCWSTR pFullName,
1584 LPCWSTR pAssemblyName,
1585 LPCUTF8 pMessageArg,
1587 : EEException(kTypeLoadException),
1588 m_pAssemblyName(pAssemblyName),
1589 m_pMessageArg(SString::Utf8, pMessageArg),
1590 m_resIDWhy(resIDWhy)
1600 MAKE_UTF8PTR_FROMWIDE(name, pFullName);
1601 m_fullName.SetUTF8(name);
1604 void EETypeLoadException::GetMessage(SString &result)
1606 WRAPPER_NO_CONTRACT;
1607 GetResourceMessage(IDS_CLASSLOAD_GENERAL, result,
1608 m_fullName, m_pAssemblyName, m_pMessageArg);
1611 OBJECTREF EETypeLoadException::CreateThrowable()
1613 #ifdef CROSSGEN_COMPILE
1626 MethodTable *pMT = MscorlibBinder::GetException(kTypeLoadException);
1629 OBJECTREF pNewException;
1630 STRINGREF pNewAssemblyString;
1631 STRINGREF pNewClassString;
1632 STRINGREF pNewMessageArgString;
1634 ZeroMemory(&gc, sizeof(gc));
1635 GCPROTECT_BEGIN(gc);
1637 gc.pNewClassString = StringObject::NewString(m_fullName);
1639 if (!m_pMessageArg.IsEmpty())
1640 gc.pNewMessageArgString = StringObject::NewString(m_pMessageArg);
1642 if (!m_pAssemblyName.IsEmpty())
1643 gc.pNewAssemblyString = StringObject::NewString(m_pAssemblyName);
1645 gc.pNewException = AllocateObject(pMT);
1647 MethodDesc* pMD = MemberLoader::FindMethod(gc.pNewException->GetMethodTable(),
1648 COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_Str_Int_RetVoid);
1652 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1653 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1656 MethodDescCallSite exceptionCtor(pMD);
1659 ObjToArgSlot(gc.pNewException),
1660 ObjToArgSlot(gc.pNewClassString),
1661 ObjToArgSlot(gc.pNewAssemblyString),
1662 ObjToArgSlot(gc.pNewMessageArgString),
1663 (ARG_SLOT)m_resIDWhy,
1666 exceptionCtor.Call(args);
1670 return gc.pNewException;
1674 // ---------------------------------------------------------------------------
1675 // EEFileLoadException is an EE exception subclass representing a file loading
1677 // ---------------------------------------------------------------------------
1678 EEFileLoadException::EEFileLoadException(const SString &name, HRESULT hr, void *pFusionLog, Exception *pInnerException/* = NULL*/)
1679 : EEException(GetFileLoadKind(hr)),
1681 m_pFusionLog(pFusionLog),
1692 // We don't want to wrap IsTransient() exceptions. The caller should really have checked this
1693 // before invoking the ctor.
1694 _ASSERTE(pInnerException == NULL || !(pInnerException->IsTransient()));
1695 m_innerException = pInnerException ? pInnerException->DomainBoundClone() : NULL;
1697 if (m_name.IsEmpty())
1699 WCHAR wszTemplate[30];
1700 if (FAILED(UtilLoadStringRC(IDS_EE_NAME_UNKNOWN,
1702 sizeof(wszTemplate)/sizeof(wszTemplate[0]),
1705 wszTemplate[0] = W('\0');
1708 m_name.Set(wszTemplate);
1713 EEFileLoadException::~EEFileLoadException()
1715 STATIC_CONTRACT_NOTHROW;
1716 STATIC_CONTRACT_GC_NOTRIGGER;
1722 void EEFileLoadException::SetFileName(const SString &fileName, BOOL removePath)
1732 //<TODO>@TODO: security: It would be nice for debugging purposes if the
1733 // user could have the full path, if the user has the right permission.</TODO>
1736 SString::CIterator i = fileName.End();
1738 if (fileName.FindBack(i, W('\\')))
1741 if (fileName.FindBack(i, W('/')))
1744 m_name.Set(fileName, i, fileName.End());
1747 m_name.Set(fileName);
1750 void EEFileLoadException::GetMessage(SString &result)
1752 WRAPPER_NO_CONTRACT;
1755 GetHRMsg(m_hr, sHR);
1756 GetResourceMessage(GetResourceIDForFileLoadExceptionHR(m_hr), result, m_name, sHR);
1759 void EEFileLoadException::GetName(SString &result)
1761 WRAPPER_NO_CONTRACT;
1767 RuntimeExceptionKind EEFileLoadException::GetFileLoadKind(HRESULT hr)
1777 if (Assembly::FileNotFound(hr))
1778 return kFileNotFoundException;
1781 // Make sure this matches the list in rexcep.h
1782 if ((hr == COR_E_BADIMAGEFORMAT) ||
1783 (hr == CLDB_E_FILE_OLDVER) ||
1784 (hr == CLDB_E_INDEX_NOTFOUND) ||
1785 (hr == CLDB_E_FILE_CORRUPT) ||
1786 (hr == COR_E_NEWER_RUNTIME) ||
1787 (hr == COR_E_ASSEMBLYEXPECTED) ||
1788 (hr == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT)) ||
1789 (hr == HRESULT_FROM_WIN32(ERROR_EXE_MARKED_INVALID)) ||
1790 (hr == CORSEC_E_INVALID_IMAGE_FORMAT) ||
1791 (hr == HRESULT_FROM_WIN32(ERROR_NOACCESS)) ||
1792 (hr == HRESULT_FROM_WIN32(ERROR_INVALID_ORDINAL)) ||
1793 (hr == HRESULT_FROM_WIN32(ERROR_INVALID_DLL)) ||
1794 (hr == HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT)) ||
1795 (hr == (HRESULT) IDS_CLASSLOAD_32BITCLRLOADING64BITASSEMBLY) ||
1796 (hr == COR_E_LOADING_REFERENCE_ASSEMBLY) ||
1797 (hr == META_E_BAD_SIGNATURE) ||
1798 (hr == COR_E_LOADING_WINMD_REFERENCE_ASSEMBLY))
1799 return kBadImageFormatException;
1802 if ((hr == E_OUTOFMEMORY) || (hr == NTE_NO_MEMORY))
1803 return kOutOfMemoryException;
1805 return kFileLoadException;
1810 OBJECTREF EEFileLoadException::CreateThrowable()
1812 #ifdef CROSSGEN_COMPILE
1825 // Fetch any log info from the fusion log
1828 OBJECTREF pNewException;
1829 STRINGREF pNewFileString;
1830 STRINGREF pFusLogString;
1832 ZeroMemory(&gc, sizeof(gc));
1833 GCPROTECT_BEGIN(gc);
1835 gc.pNewFileString = StringObject::NewString(m_name);
1836 gc.pFusLogString = StringObject::NewString(logText);
1837 gc.pNewException = AllocateObject(MscorlibBinder::GetException(m_kind));
1839 MethodDesc* pMD = MemberLoader::FindMethod(gc.pNewException->GetMethodTable(),
1840 COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_Int_RetVoid);
1844 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1845 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1848 MethodDescCallSite exceptionCtor(pMD);
1851 ObjToArgSlot(gc.pNewException),
1852 ObjToArgSlot(gc.pNewFileString),
1853 ObjToArgSlot(gc.pFusLogString),
1857 exceptionCtor.Call(args);
1861 return gc.pNewException;
1867 BOOL EEFileLoadException::CheckType(Exception* ex)
1869 LIMITED_METHOD_CONTRACT;
1871 // used as typeof(EEFileLoadException)
1872 RuntimeExceptionKind kind = kException;
1873 if (ex->IsType(EEException::GetType()))
1874 kind=((EEException*)ex)->m_kind;
1879 case kFileLoadException:
1880 case kFileNotFoundException:
1881 case kBadImageFormatException:
1889 // <TODO>@todo: ideally we would use inner exceptions with these routines</TODO>
1894 void DECLSPEC_NORETURN EEFileLoadException::Throw(AssemblySpec *pSpec, HRESULT hr, Exception *pInnerException/* = NULL*/)
1904 if (hr == COR_E_THREADABORTED)
1905 COMPlusThrow(kThreadAbortException);
1906 if (hr == E_OUTOFMEMORY)
1908 #ifdef FEATURE_COMINTEROP
1909 if ((hr == RO_E_METADATA_NAME_NOT_FOUND) || (hr == CLR_E_BIND_TYPE_NOT_FOUND))
1910 { // These error codes behave like FileNotFound, but are exposed as TypeLoadException
1911 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), pInnerException);
1913 #endif //FEATURE_COMINTEROP
1916 pSpec->GetFileOrDisplayName(0, name);
1917 EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1921 void DECLSPEC_NORETURN EEFileLoadException::Throw(PEFile *pFile, HRESULT hr, Exception *pInnerException /* = NULL*/)
1931 if (hr == COR_E_THREADABORTED)
1932 COMPlusThrow(kThreadAbortException);
1933 if (hr == E_OUTOFMEMORY)
1938 if (pFile->IsAssembly())
1939 ((PEAssembly*)pFile)->GetDisplayName(name);
1941 name = StackSString(SString::Utf8, pFile->GetSimpleName());
1942 EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1947 void DECLSPEC_NORETURN EEFileLoadException::Throw(LPCWSTR path, HRESULT hr, Exception *pInnerException/* = NULL*/)
1957 if (hr == COR_E_THREADABORTED)
1958 COMPlusThrow(kThreadAbortException);
1959 if (hr == E_OUTOFMEMORY)
1962 EX_THROW_WITH_INNER(EEFileLoadException, (StackSString(path), hr), pInnerException);
1967 void DECLSPEC_NORETURN EEFileLoadException::Throw(PEAssembly *parent,
1968 const void *memory, COUNT_T size, HRESULT hr, Exception *pInnerException/* = NULL*/)
1978 if (hr == COR_E_THREADABORTED)
1979 COMPlusThrow(kThreadAbortException);
1980 if (hr == E_OUTOFMEMORY)
1984 name.Printf("%d bytes loaded from ", size);
1986 StackSString parentName;
1987 parent->GetDisplayName(parentName);
1989 name.Append(parentName);
1990 EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1993 #ifndef CROSSGEN_COMPILE
1994 // ---------------------------------------------------------------------------
1995 // EEComException methods
1996 // ---------------------------------------------------------------------------
1998 static HRESULT Undefer(EXCEPINFO *pExcepInfo)
2008 if (pExcepInfo->pfnDeferredFillIn)
2010 EXCEPINFO FilledInExcepInfo;
2012 HRESULT hr = pExcepInfo->pfnDeferredFillIn(&FilledInExcepInfo);
2015 // Free the strings in the original EXCEPINFO.
2016 if (pExcepInfo->bstrDescription)
2018 SysFreeString(pExcepInfo->bstrDescription);
2019 pExcepInfo->bstrDescription = NULL;
2021 if (pExcepInfo->bstrSource)
2023 SysFreeString(pExcepInfo->bstrSource);
2024 pExcepInfo->bstrSource = NULL;
2026 if (pExcepInfo->bstrHelpFile)
2028 SysFreeString(pExcepInfo->bstrHelpFile);
2029 pExcepInfo->bstrHelpFile = NULL;
2032 // Fill in the new data
2033 *pExcepInfo = FilledInExcepInfo;
2037 if (pExcepInfo->scode != 0)
2038 return pExcepInfo->scode;
2040 return (HRESULT)pExcepInfo->wCode;
2043 EECOMException::EECOMException(EXCEPINFO *pExcepInfo)
2044 : EEException(GetKindFromHR(Undefer(pExcepInfo)))
2046 WRAPPER_NO_CONTRACT;
2048 if (pExcepInfo->scode != 0)
2049 m_ED.hr = pExcepInfo->scode;
2051 m_ED.hr = (HRESULT)pExcepInfo->wCode;
2053 m_ED.bstrDescription = pExcepInfo->bstrDescription;
2054 m_ED.bstrSource = pExcepInfo->bstrSource;
2055 m_ED.bstrHelpFile = pExcepInfo->bstrHelpFile;
2056 m_ED.dwHelpContext = pExcepInfo->dwHelpContext;
2057 m_ED.guid = GUID_NULL;
2059 #ifdef FEATURE_COMINTEROP
2060 m_ED.bstrReference = NULL;
2061 m_ED.bstrRestrictedError = NULL;
2062 m_ED.bstrCapabilitySid = NULL;
2063 m_ED.pRestrictedErrorInfo = NULL;
2064 m_ED.bHasLanguageRestrictedErrorInfo = FALSE;
2067 // Zero the EXCEPINFO.
2068 memset(pExcepInfo, NULL, sizeof(EXCEPINFO));
2071 EECOMException::EECOMException(ExceptionData *pData)
2072 : EEException(GetKindFromHR(pData->hr))
2074 LIMITED_METHOD_CONTRACT;
2079 ZeroMemory(pData, sizeof(ExceptionData));
2082 EECOMException::EECOMException(
2084 IErrorInfo *pErrInfo,
2085 bool fUseCOMException, // use System.Runtime.InteropServices.COMException as the default exception type (means as much as !IsWinRT)
2086 IRestrictedErrorInfo* pRestrictedErrInfo,
2087 BOOL bHasLanguageRestrictedErrInfo
2088 COMMA_INDEBUG(BOOL bCheckInProcCCWTearOff))
2089 : EEException(GetKindFromHR(hr, !fUseCOMException))
2091 WRAPPER_NO_CONTRACT;
2093 #ifdef FEATURE_COMINTEROP
2094 // Must use another path for managed IErrorInfos...
2095 // note that this doesn't cover out-of-proc managed IErrorInfos.
2096 _ASSERTE(!bCheckInProcCCWTearOff || !IsInProcCCWTearOff(pErrInfo));
2097 _ASSERTE(pRestrictedErrInfo == NULL || !bCheckInProcCCWTearOff || !IsInProcCCWTearOff(pRestrictedErrInfo));
2098 #endif // FEATURE_COMINTEROP
2101 m_ED.bstrDescription = NULL;
2102 m_ED.bstrSource = NULL;
2103 m_ED.bstrHelpFile = NULL;
2104 m_ED.dwHelpContext = NULL;
2105 m_ED.guid = GUID_NULL;
2107 #ifdef FEATURE_COMINTEROP
2108 m_ED.bstrReference = NULL;
2109 m_ED.bstrRestrictedError = NULL;
2110 m_ED.bstrCapabilitySid = NULL;
2111 m_ED.pRestrictedErrorInfo = NULL;
2112 m_ED.bHasLanguageRestrictedErrorInfo = bHasLanguageRestrictedErrInfo;
2115 FillExceptionData(&m_ED, pErrInfo, pRestrictedErrInfo);
2118 BOOL EECOMException::GetThrowableMessage(SString &result)
2128 #ifdef FEATURE_COMINTEROP
2129 if (m_ED.bstrDescription != NULL || m_ED.bstrRestrictedError != NULL)
2131 // For cross language WinRT exceptions, general information will be available in the bstrDescription,
2132 // which is populated from IErrorInfo::GetDescription and more specific information will be available
2133 // in the bstrRestrictedError which comes from the IRestrictedErrorInfo. If both are available, we
2134 // need to concatinate them to produce the final exception message.
2138 // If we have a restricted description, start our message with that
2139 if (m_ED.bstrDescription != NULL)
2141 SString generalInformation(m_ED.bstrDescription, SysStringLen(m_ED.bstrDescription));
2142 result.Append(generalInformation);
2144 // If we're also going to have a specific error message, append a newline to separate the two
2145 if (m_ED.bstrRestrictedError != NULL)
2147 result.Append(W("\r\n"));
2151 // If we have additional error information, attach it to the end of the string
2152 if (m_ED.bstrRestrictedError != NULL)
2154 SString restrictedDescription(m_ED.bstrRestrictedError, SysStringLen(m_ED.bstrRestrictedError));
2155 result.Append(restrictedDescription);
2158 #else // !FEATURE_COMINTEROP
2159 if (m_ED.bstrDescription != NULL)
2161 result.Set(m_ED.bstrDescription, SysStringLen(m_ED.bstrDescription));
2163 #endif // FEATURE_COMINTEROP
2166 GenerateTopLevelHRExceptionMessage(GetHR(), result);
2172 EECOMException::~EECOMException()
2174 WRAPPER_NO_CONTRACT;
2176 FreeExceptionData(&m_ED);
2179 HRESULT EECOMException::GetHR()
2181 LIMITED_METHOD_CONTRACT;
2186 OBJECTREF EECOMException::CreateThrowable()
2196 OBJECTREF throwable = NULL;
2197 GCPROTECT_BEGIN(throwable);
2199 // Note that this will pick up the message from GetThrowableMessage
2200 throwable = EEException::CreateThrowable();
2202 // Set the _helpURL field in the exception.
2203 if (m_ED.bstrHelpFile)
2205 // Create the help link from the help file and the help context.
2206 STRINGREF helpStr = NULL;
2207 if (m_ED.dwHelpContext != 0)
2209 // We have a non 0 help context so use it to form the help link.
2211 strMessage.Printf(W("%s#%d"), m_ED.bstrHelpFile, m_ED.dwHelpContext);
2212 helpStr = StringObject::NewString(strMessage);
2216 // The help context is 0 so we simply use the help file to from the help link.
2217 helpStr = StringObject::NewString(m_ED.bstrHelpFile, SysStringLen(m_ED.bstrHelpFile));
2220 ((EXCEPTIONREF)throwable)->SetHelpURL(helpStr);
2223 // Set the Source field in the exception.
2224 STRINGREF sourceStr = NULL;
2225 if (m_ED.bstrSource)
2227 sourceStr = StringObject::NewString(m_ED.bstrSource, SysStringLen(m_ED.bstrSource));
2231 // for now set a null source
2232 sourceStr = StringObject::GetEmptyString();
2234 ((EXCEPTIONREF)throwable)->SetSource(sourceStr);
2236 #ifdef FEATURE_COMINTEROP
2238 // Support for WinRT interface IRestrictedErrorInfo
2240 if (m_ED.pRestrictedErrorInfo)
2244 STRINGREF RestrictedErrorRef;
2245 STRINGREF ReferenceRef;
2246 STRINGREF RestrictedCapabilitySidRef;
2247 OBJECTREF RestrictedErrorInfoObjRef;
2249 ZeroMemory(&gc, sizeof(gc));
2251 GCPROTECT_BEGIN(gc);
2255 gc.RestrictedErrorRef = StringObject::NewString(
2256 m_ED.bstrRestrictedError,
2257 SysStringLen(m_ED.bstrRestrictedError)
2259 gc.ReferenceRef = StringObject::NewString(
2261 SysStringLen(m_ED.bstrReference)
2264 gc.RestrictedCapabilitySidRef = StringObject::NewString(
2265 m_ED.bstrCapabilitySid,
2266 SysStringLen(m_ED.bstrCapabilitySid)
2269 // Convert IRestrictedErrorInfo into a managed object - don't care whether it is a RCW/CCW
2270 GetObjectRefFromComIP(
2271 &gc.RestrictedErrorInfoObjRef,
2272 m_ED.pRestrictedErrorInfo, // IUnknown *
2275 ObjFromComIP::CLASS_IS_HINT | ObjFromComIP::IGNORE_WINRT_AND_SKIP_UNBOXING
2279 // Call Exception.AddExceptionDataForRestrictedErrorInfo and put error information
2280 // from IRestrictedErrorInfo on Exception.Data
2282 MethodDescCallSite addExceptionDataForRestrictedErrorInfo(
2283 METHOD__EXCEPTION__ADD_EXCEPTION_DATA_FOR_RESTRICTED_ERROR_INFO,
2289 ObjToArgSlot(throwable),
2290 ObjToArgSlot(gc.RestrictedErrorRef),
2291 ObjToArgSlot(gc.ReferenceRef),
2292 ObjToArgSlot(gc.RestrictedCapabilitySidRef),
2293 ObjToArgSlot(gc.RestrictedErrorInfoObjRef),
2294 BoolToArgSlot(m_ED.bHasLanguageRestrictedErrorInfo)
2297 addExceptionDataForRestrictedErrorInfo.Call(Args);
2302 // IDictionary.Add may throw. Ignore all non terminal exceptions
2304 EX_END_CATCH(RethrowTerminalExceptions)
2308 #endif // FEATURE_COMINTEROP
2316 // ---------------------------------------------------------------------------
2317 // ObjrefException methods
2318 // ---------------------------------------------------------------------------
2320 ObjrefException::ObjrefException()
2322 LIMITED_METHOD_CONTRACT;
2325 ObjrefException::ObjrefException(OBJECTREF throwable)
2335 SetThrowableHandle(GetAppDomain()->CreateHandle(throwable));
2338 // --------------------------------------------------------------------------------------------------------------------------------------
2339 // ObjrefException and CLRLastThrownObjectException are never set as inner exception for an internal CLR exception.
2340 // As a result, if we invoke DomainBoundClone against an exception, it will never reach these implementations.
2341 // If someone does set them as inner, it will trigger contract violation - which is valid and should be fixed by whoever
2342 // set them as inner since Exception::DomainBoundClone is implemented in utilcode that has to work outside the context of CLR and thus,
2343 // should never trigger GC. This is also why GC_TRIGGERS is not supported in utilcode (refer to its definition in contracts.h).
2344 // --------------------------------------------------------------------------------------------------------------------------------------
2345 Exception *ObjrefException::DomainBoundCloneHelper()
2355 return new ObjrefException(GetThrowable());
2358 // ---------------------------------------------------------------------------
2359 // CLRLastThrownException methods
2360 // ---------------------------------------------------------------------------
2362 CLRLastThrownObjectException::CLRLastThrownObjectException()
2364 LIMITED_METHOD_CONTRACT;
2367 Exception *CLRLastThrownObjectException::CloneHelper()
2369 WRAPPER_NO_CONTRACT;
2371 return new ObjrefException(GetThrowable());
2374 // ---------------------------------------------------------------------------
2375 // See ObjrefException::DomainBoundCloneHelper comments.
2376 // ---------------------------------------------------------------------------
2377 Exception *CLRLastThrownObjectException::DomainBoundCloneHelper()
2387 return new ObjrefException(GetThrowable());
2390 OBJECTREF CLRLastThrownObjectException::CreateThrowable()
2400 DEBUG_STMT(Validate());
2402 return GetThread()->LastThrownObject();
2403 } // OBJECTREF CLRLastThrownObjectException::CreateThrowable()
2406 CLRLastThrownObjectException* CLRLastThrownObjectException::Validate()
2415 // Have to be in coop for GCPROTECT_BEGIN.
2418 OBJECTREF throwable = NULL;
2420 GCPROTECT_BEGIN(throwable);
2422 Thread * pThread = GetThread();
2423 throwable = pThread->LastThrownObject();
2425 DWORD dwCurrentExceptionCode = GetCurrentExceptionCode();
2427 if (dwCurrentExceptionCode == BOOTUP_EXCEPTION_COMPLUS)
2429 // BOOTUP_EXCEPTION_COMPLUS can be thrown when a thread setup is failed due to reasons like
2430 // runtime is being shutdown or managed code is no longer allowed to be executed.
2432 // If this exception is caught in EX_CATCH, there may not be any LTO setup since:
2434 // 1) It is setup against the thread that may not exist (due to thread setup failure)
2435 // 2) This exception is raised using RaiseException (and not the managed raise implementation in RaiseTheExceptionInternalOnly)
2436 // since managed code may not be allowed to be executed.
2438 // However, code inside EX_CATCH is abstracted of this specificity of EH and thus, will attempt to fetch the throwble
2439 // using GET_THROWABLE that will, in turn, use the GET_EXCEPTION macro to fetch the C++ exception type corresponding to the caught exception.
2440 // Since BOOTUP_EXCEPTION_COMPLUS is a SEH exception, this (C++ exception) type will be CLRLastThrownObjectException.
2442 // GET_EXCEPTION will call this method to validate the presence of LTO for a SEH exception caught by EX_CATCH. This is based upon the assumption
2443 // that by the time a SEH exception is caught in EX_CATCH, the LTO is setup:
2445 // A) For a managed exception thrown, this is done by RaiseTheExceptionInternalOnly.
2446 // B) For a SEH exception that enters managed code from a PInvoke call, this is done by calling SafeSetThrowables after the corresponding throwable is created
2447 // using CreateCOMPlusExceptionObject.
2449 // Clearly, BOOTUP_EXCEPTION_COMPLUS can also be caught in EX_CATCH. However:
2451 // (A) above is not applicable since the exception is raised using RaiseException.
2453 // (B) scenario is interesting. On x86, CPFH_FirstPassHandler also invokes CLRVectoredExceptionHandler (for legacy purposes) that, in Phase3, will return EXCEPTION_CONTINUE_SEARCH for
2454 // BOOTUP_EXCEPTION_COMPLUS. This will result in CPFH_FirstPassHandler to simply return from the x86 personality routine without invoking CreateCOMPlusExceptionObject even if managed
2455 // frames were present on the stack (as happens in PInvoke). Thus, there is no LTO setup for X86.
2457 // On X64, the personality routine does not invoke VEH but simply creates the exception tracker and will also create throwable and setup LTO if managed frames are present on the stack.
2458 // But if there are no managed frames on the stack, then the managed personality routine may or may not get invoked (depending upon if any VM native function is present on the stack whose
2459 // personality routine is the managed personality routine). Thus, we may have a case of LTO not being present on X64 as well, for this exception.
2461 // Thus, when we see BOOTUP_EXCEPTION_COMPLUS, we will return back successfully (without doing anything) to imply a successful LTO validation. Eventually, a valid
2462 // throwable will be returned to the user of GET_THROWABLE (for details, trace the call to CLRException::GetThrowableFromException for CLRLastThrownObjectException type).
2464 // This also ensures that the handling of BOOTUP_EXCEPTION_COMPLUS is now insync between the chk and fre builds in terms of the throwable returned.
2466 else if (throwable == NULL)
2467 { // If there isn't a LastThrownObject at all, that's a problem for GetLastThrownObject
2468 // We've lost track of the exception's type. Raise an assert. (This is configurable to allow
2469 // stress labs to turn off the assert.)
2471 static int iSuppress = -1;
2472 if (iSuppress == -1)
2473 iSuppress = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuppressLostExceptionTypeAssert);
2476 // Raising an assert message can cause a mode violation.
2477 CONTRACT_VIOLATION(ModeViolation);
2479 // Use DbgAssertDialog to get the formatting right.
2480 DbgAssertDialog(__FILE__, __LINE__,
2481 "The 'LastThrownObject' should not be, but is, NULL.\n"
2482 "The runtime may have lost track of the type of an exception in flight.\n"
2483 "Please get a good stack trace, find the caller of Validate, and file a bug against the owner.\n\n"
2484 "To suppress this assert 'set COMPlus_SuppressLostExceptionTypeAssert=1'");
2491 } // CLRLastThrownObjectException* CLRLastThrownObjectException::Validate()
2494 // ---------------------------------------------------------------------------
2495 // Helper function to get an exception from outside the exception.
2496 // Create and return a LastThrownObjectException. Its virtual destructor
2497 // will clean up properly.
2498 void GetLastThrownObjectExceptionFromThread_Internal(Exception **ppException)
2508 // If the Thread has been set up, then the LastThrownObject may make sense...
2511 // give back an object that knows about Threads and their exceptions.
2512 *ppException = new CLRLastThrownObjectException();
2516 // but if no Thread, don't pretend to know about LastThrownObject.
2517 *ppException = NULL;
2520 } // void GetLastThrownObjectExceptionFromThread_Internal()
2522 #endif // CROSSGEN_COMPILE
2524 //@TODO: Make available generally?
2525 // Wrapper class to encapsulate both array pointer and element count.
2526 template <typename T>
2527 class ArrayReference
2530 typedef T value_type;
2531 typedef const typename std::remove_const<T>::type const_value_type;
2533 typedef ArrayDPTR(value_type) array_type;
2534 typedef ArrayDPTR(const_value_type) const_array_type;
2536 // Constructor taking array pointer and size.
2537 ArrayReference(array_type array, size_t size)
2538 : _array(dac_cast<array_type>(array))
2540 { LIMITED_METHOD_CONTRACT; }
2542 // Constructor taking a statically sized array by reference.
2544 ArrayReference(T (&array)[N])
2545 : _array(dac_cast<array_type>(&array[0]))
2547 { LIMITED_METHOD_CONTRACT; }
2549 // Copy constructor.
2550 ArrayReference(ArrayReference const & other)
2551 : _array(other._array)
2552 , _size(other._size)
2553 { LIMITED_METHOD_CONTRACT; }
2556 template <typename IdxT>
2557 T & operator[](IdxT idx)
2558 { LIMITED_METHOD_CONTRACT; _ASSERTE(idx < _size); return _array[idx]; }
2560 // Implicit conversion operators.
2561 operator array_type()
2562 { LIMITED_METHOD_CONTRACT; return _array; }
2564 operator const_array_type() const
2565 { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array); }
2567 // Returns the array element count.
2569 { LIMITED_METHOD_CONTRACT; return _size; }
2571 // Iteration methods and types.
2572 typedef array_type iterator;
2575 { LIMITED_METHOD_CONTRACT; return _array; }
2578 { LIMITED_METHOD_CONTRACT; return _array + _size; }
2580 typedef const_array_type const_iterator;
2582 const_iterator begin() const
2583 { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array); }
2585 const_iterator end() const
2586 { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array) + _size; }
2593 ArrayReference<const HRESULT> GetHRESULTsForExceptionKind(RuntimeExceptionKind kind)
2595 LIMITED_METHOD_CONTRACT;
2599 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) \
2601 return ArrayReference<const HRESULT>(s_##reKind##HRs); \
2603 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
2604 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
2608 _ASSERTE(!"Unknown exception kind!");
2613 return ArrayReference<const HRESULT>(nullptr, 0);
2616 bool IsHRESULTForExceptionKind(HRESULT hr, RuntimeExceptionKind kind)
2618 LIMITED_METHOD_CONTRACT;
2620 ArrayReference<const HRESULT> rgHR = GetHRESULTsForExceptionKind(kind);
2621 for (ArrayReference<const HRESULT>::iterator i = rgHR.begin(); i != rgHR.end(); ++i)