[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / clrex.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5
6 //
7 // ---------------------------------------------------------------------------
8 // Clrex.cpp
9 // ---------------------------------------------------------------------------
10
11
12 #include "common.h"
13 #include "clrex.h"
14 #include "field.h"
15 #include "eetoprofinterfacewrapper.inl"
16 #include "typestring.h"
17 #include "sigformat.h"
18 #include "eeconfig.h"
19 #include "frameworkexceptionloader.h"
20
21 #ifdef WIN64EXCEPTIONS
22 #include "exceptionhandling.h"
23 #endif // WIN64EXCEPTIONS
24
25 #ifdef FEATURE_COMINTEROP
26 #include "interoputil.inl"
27 #endif // FEATURE_COMINTEROP
28
29 // ---------------------------------------------------------------------------
30 // CLRException methods
31 // ---------------------------------------------------------------------------
32
33 CLRException::~CLRException()
34 {
35     CONTRACTL
36     {
37         GC_NOTRIGGER;
38         NOTHROW;
39         MODE_ANY;
40         if (GetThrowableHandle() == NULL)
41         {
42             CANNOT_TAKE_LOCK;
43         }
44         else
45         {
46             CAN_TAKE_LOCK;         // because of DestroyHandle
47         }
48     }
49     CONTRACTL_END;
50     
51 #ifndef CROSSGEN_COMPILE
52     OBJECTHANDLE throwableHandle = GetThrowableHandle();
53     if (throwableHandle != NULL)
54     {
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);
59     }
60 #endif
61 }
62
63 OBJECTREF CLRException::GetThrowable()
64 {
65     CONTRACTL
66     {
67         GC_TRIGGERS;
68         NOTHROW;
69         MODE_COOPERATIVE;
70         FORBID_FAULT;
71     }
72     CONTRACTL_END;
73
74 #ifdef CROSSGEN_COMPILE
75     _ASSERTE(false);
76     return NULL;
77 #else
78     OBJECTREF throwable = NULL;
79
80     if (NingenEnabled())
81     {
82         return NULL;
83     }
84
85     Thread *pThread = GetThread();
86
87     if (pThread->IsRudeAbortInitiated()) {
88         return GetPreallocatedRudeThreadAbortException();
89     }
90
91     if ((IsType(CLRLastThrownObjectException::GetType()) && 
92          pThread->LastThrownObject() == GetPreallocatedStackOverflowException()))
93     {
94         return GetPreallocatedStackOverflowException();
95     }
96
97     OBJECTHANDLE oh = GetThrowableHandle();
98     if (oh != NULL)
99     {
100         return ObjectFromHandle(oh);
101     }
102    
103     Exception *pLastException = pThread->m_pCreatingThrowableForException;
104     if (pLastException != NULL)
105     {
106         if (IsSameInstanceType(pLastException))
107         {
108 #if defined(_DEBUG)
109             static int BreakOnExceptionInGetThrowable = -1;
110             if (BreakOnExceptionInGetThrowable == -1)
111             {
112                 BreakOnExceptionInGetThrowable = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnExceptionInGetThrowable);
113             }
114             if (BreakOnExceptionInGetThrowable)
115             {
116                 _ASSERTE(!"BreakOnExceptionInGetThrowable");
117             }
118             LOG((LF_EH, LL_INFO100, "GetThrowable: Exception in GetThrowable, translating to a preallocated exception.\n"));
119 #endif // _DEBUG
120             // Look at the type of GET_EXCEPTION() and see if it is OOM or SO.
121             if (IsPreallocatedOOMException())
122             {
123                 throwable = GetPreallocatedOutOfMemoryException();
124             }
125             else if (GetInstanceType() == EEException::GetType() && GetHR() == COR_E_THREADABORTED)
126             {
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();
134             }
135             else
136             {
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.
142                 // 
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.
145                 //
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");
149                 
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();
153             }
154         }
155     }
156
157     GCPROTECT_BEGIN(throwable);
158
159     if (throwable == NULL)
160     {
161         class RestoreLastException
162         {
163             Thread *m_pThread;
164             Exception *m_pLastException;
165         public:
166             RestoreLastException(Thread *pThread, Exception *pException)
167             {
168                 m_pThread = pThread;
169                 m_pLastException = m_pThread->m_pCreatingThrowableForException;
170                 m_pThread->m_pCreatingThrowableForException = pException;
171             }
172             ~RestoreLastException()
173             {
174                 m_pThread->m_pCreatingThrowableForException = m_pLastException;
175             }
176         };
177         
178         RestoreLastException restore(pThread, this);
179
180         EX_TRY
181         {
182             FAULT_NOT_FATAL();
183             throwable = CreateThrowable();
184         }
185         EX_CATCH
186         {
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.
200
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();
205
206             if (GetHR() == COR_E_THREADABORTED)
207             {
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();
215             }
216             else
217             {
218                 throwable = CLRException::GetThrowableFromException(pException);
219             }
220         }
221         EX_END_CATCH(SwallowAllExceptions)
222         
223     }
224     
225     {
226         if (throwable == NULL)
227         {
228             STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowable: We have failed to track exceptions accurately through the system.\n");
229
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.
234
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.
237             // _ASSERTE(FALSE);
238
239             throwable = GetPreallocatedOutOfMemoryException();
240         }
241
242         EX_TRY
243         {
244             SetThrowableHandle(GetAppDomain()->CreateHandle(throwable));
245             if (m_innerException != NULL && !CLRException::IsPreallocatedExceptionObject(throwable))
246             {
247                 // Only set inner exception if the exception is not preallocated.
248                 FAULT_NOT_FATAL();
249
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);
254             }
255
256         }
257         EX_CATCH
258         {
259             // No matter... we just don't get to cache the throwable.
260         }
261         EX_END_CATCH(SwallowAllExceptions)
262     }
263
264     GCPROTECT_END();
265
266     return throwable;
267 #endif
268 }
269
270 HRESULT CLRException::GetHR()
271 {
272     CONTRACTL
273     {
274         DISABLED(NOTHROW);
275         GC_TRIGGERS;
276         MODE_ANY;
277     }
278     CONTRACTL_END;
279
280     GCX_COOP();
281     return GetExceptionHResult(GetThrowable());
282 }
283
284 #ifdef FEATURE_COMINTEROP
285 HRESULT CLRException::SetErrorInfo()
286 {
287    CONTRACTL
288     {
289         GC_TRIGGERS;
290         NOTHROW;
291         MODE_ANY;
292     }
293     CONTRACTL_END;
294
295     HRESULT hr = S_OK;
296
297     IErrorInfo *pErrorInfo = NULL;
298
299     // Try to get IErrorInfo
300     EX_TRY
301     {
302         pErrorInfo = GetErrorInfo();
303     }
304     EX_CATCH
305     {
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();
309         pErrorInfo = NULL;
310         LOG((LF_EH, LL_INFO100, "CLRException::SetErrorInfo: caught exception (hr = %08X) while trying to get IErrorInfo\n", hr));
311     }
312     EX_END_CATCH(SwallowAllExceptions)
313
314     if (!pErrorInfo)
315     {
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.
319         return hr;
320     }
321     else
322     {
323         GCX_PREEMP();
324
325         EX_TRY
326         {
327             ::SetErrorInfo(0, pErrorInfo);
328             pErrorInfo->Release();
329
330             // Success in setting the ErrorInfo on the thread
331             hr = S_OK;
332         }
333         EX_CATCH
334         {
335             hr = GET_EXCEPTION()->GetHR();
336             // Log the failure
337             LOG((LF_EH, LL_INFO100, "CLRException::SetErrorInfo: caught exception (hr = %08X) while trying to set IErrorInfo\n", hr));
338         }
339         EX_END_CATCH(SwallowAllExceptions)
340     }
341
342     return hr;
343 }
344
345 IErrorInfo *CLRException::GetErrorInfo()
346 {
347     CONTRACTL
348     {
349         GC_TRIGGERS;
350         THROWS;
351         MODE_ANY;
352     }
353     CONTRACTL_END;
354     
355     IErrorInfo *pErrorInfo = NULL;
356
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).
360     if (g_fComStarted)
361     {
362         // Get errorinfo only when our SO probe succeeds
363         {
364             // Switch to coop mode since GetComIPFromObjectRef requires that
365             // and we could be here in any mode...
366             GCX_COOP();
367
368             OBJECTREF e = NULL;
369             GCPROTECT_BEGIN(e);
370
371             e = GetThrowable();
372         
373             if (e != NULL)
374             {
375                 pErrorInfo = (IErrorInfo *)GetComIPFromObjectRef(&e, IID_IErrorInfo);
376             }
377
378             GCPROTECT_END();
379         }
380     }
381     else
382     {
383         // Write to the log incase COM isnt initialized.
384         LOG((LF_EH, LL_INFO100, "CLRException::GetErrorInfo: exiting since COM is not initialized.\n"));
385     }
386 #endif //CROSSGEN_COMPILE
387
388     // return the IErrorInfo we got...
389     return pErrorInfo;
390 }
391 #else   // FEATURE_COMINTEROP
392 IErrorInfo *CLRException::GetErrorInfo()
393 {
394     LIMITED_METHOD_CONTRACT;
395     return NULL;
396 }
397 HRESULT CLRException::SetErrorInfo()
398 {
399     LIMITED_METHOD_CONTRACT;
400
401     return S_OK;
402  }
403 #endif  // FEATURE_COMINTEROP
404
405 void CLRException::GetMessage(SString &result)
406 {
407     CONTRACTL
408     {
409         GC_TRIGGERS;
410         THROWS;
411         MODE_ANY;
412     }
413     CONTRACTL_END;
414     
415 #ifndef CROSSGEN_COMPILE
416     GCX_COOP();
417
418     OBJECTREF e = GetThrowable();
419     if (e != NULL)
420     {
421         _ASSERTE(IsException(e->GetMethodTable()));
422
423         GCPROTECT_BEGIN (e);
424
425         STRINGREF message = ((EXCEPTIONREF)e)->GetMessage();
426
427         if (!message)
428             result.Clear();
429         else
430             message->GetSString(result);
431
432         GCPROTECT_END ();
433     }
434 #endif
435 }
436
437 #ifndef CROSSGEN_COMPILE
438 OBJECTREF CLRException::GetPreallocatedBaseException()
439 {
440     WRAPPER_NO_CONTRACT;
441     _ASSERTE(g_pPreallocatedBaseException != NULL);
442     return ObjectFromHandle(g_pPreallocatedBaseException);
443 }
444
445 OBJECTREF CLRException::GetPreallocatedOutOfMemoryException()
446 {
447     WRAPPER_NO_CONTRACT;
448     _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
449     return ObjectFromHandle(g_pPreallocatedOutOfMemoryException);
450 }
451
452 OBJECTREF CLRException::GetPreallocatedStackOverflowException()
453 {
454     WRAPPER_NO_CONTRACT;
455     _ASSERTE(g_pPreallocatedStackOverflowException != NULL);
456     return ObjectFromHandle(g_pPreallocatedStackOverflowException);
457 }
458
459 OBJECTREF CLRException::GetPreallocatedExecutionEngineException()
460 {
461     WRAPPER_NO_CONTRACT;
462     _ASSERTE(g_pPreallocatedExecutionEngineException != NULL);
463     return ObjectFromHandle(g_pPreallocatedExecutionEngineException);
464 }
465
466 OBJECTREF CLRException::GetPreallocatedRudeThreadAbortException()
467 {
468     WRAPPER_NO_CONTRACT;
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);
473 }
474
475 OBJECTREF CLRException::GetPreallocatedThreadAbortException()
476 {
477     WRAPPER_NO_CONTRACT;
478     _ASSERTE(g_pPreallocatedThreadAbortException);
479     return ObjectFromHandle(g_pPreallocatedThreadAbortException);
480 }
481
482 OBJECTHANDLE CLRException::GetPreallocatedOutOfMemoryExceptionHandle()
483 {
484     LIMITED_METHOD_CONTRACT;
485     _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
486     return g_pPreallocatedOutOfMemoryException;
487 }
488
489 OBJECTHANDLE CLRException::GetPreallocatedThreadAbortExceptionHandle()
490 {
491     LIMITED_METHOD_CONTRACT;
492     _ASSERTE(g_pPreallocatedThreadAbortException != NULL);
493     return g_pPreallocatedThreadAbortException;
494 }
495
496 OBJECTHANDLE CLRException::GetPreallocatedRudeThreadAbortExceptionHandle()
497 {
498     LIMITED_METHOD_CONTRACT;
499     _ASSERTE(g_pPreallocatedRudeThreadAbortException != NULL);
500     return g_pPreallocatedRudeThreadAbortException;
501 }
502
503 OBJECTHANDLE CLRException::GetPreallocatedStackOverflowExceptionHandle()
504 {
505     LIMITED_METHOD_CONTRACT;
506     _ASSERTE(g_pPreallocatedStackOverflowException != NULL);
507     return g_pPreallocatedStackOverflowException;
508 }
509
510 OBJECTHANDLE CLRException::GetPreallocatedExecutionEngineExceptionHandle()
511 {
512     LIMITED_METHOD_CONTRACT;
513     _ASSERTE(g_pPreallocatedExecutionEngineException != NULL);
514     return g_pPreallocatedExecutionEngineException;
515 }
516
517 //
518 // Returns TRUE if the given object ref is one of the preallocated exception objects.
519 //
520 BOOL CLRException::IsPreallocatedExceptionObject(OBJECTREF o)
521 {
522     CONTRACTL
523     {
524         NOTHROW;
525         GC_NOTRIGGER;
526         MODE_COOPERATIVE;
527         FORBID_FAULT;
528     }
529     CONTRACTL_END;
530
531     if ((o == ObjectFromHandle(g_pPreallocatedBaseException)) ||
532         (o == ObjectFromHandle(g_pPreallocatedOutOfMemoryException)) ||
533         (o == ObjectFromHandle(g_pPreallocatedStackOverflowException)) ||
534         (o == ObjectFromHandle(g_pPreallocatedExecutionEngineException)))
535     {
536         return TRUE;
537     }
538
539     // The preallocated rude thread abort exception is not always preallocated.
540     if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
541         (o == ObjectFromHandle(g_pPreallocatedRudeThreadAbortException)))
542     {
543         return TRUE;
544     }
545
546     // The preallocated rude thread abort exception is not always preallocated.
547     if ((g_pPreallocatedThreadAbortException != NULL) &&
548         (o == ObjectFromHandle(g_pPreallocatedThreadAbortException)))
549     {
550         return TRUE;
551     }
552
553     return FALSE;
554 }
555
556 //
557 // Returns TRUE if the given object ref is one of the preallocated exception handles
558 //
559 BOOL CLRException::IsPreallocatedExceptionHandle(OBJECTHANDLE h)
560 {
561     CONTRACTL
562     {
563         NOTHROW;
564         GC_NOTRIGGER;
565         MODE_ANY;
566         FORBID_FAULT;
567     }
568     CONTRACTL_END;
569
570     if ((h == g_pPreallocatedBaseException) ||
571         (h == g_pPreallocatedOutOfMemoryException) ||
572         (h == g_pPreallocatedStackOverflowException) ||
573         (h == g_pPreallocatedExecutionEngineException) ||
574         (h == g_pPreallocatedThreadAbortException))
575     {
576         return TRUE;
577     }
578
579     // The preallocated rude thread abort exception is not always preallocated.
580     if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
581         (h == g_pPreallocatedRudeThreadAbortException))
582     {
583         return TRUE;
584     }
585
586     return FALSE;
587 }
588
589 //
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.
592 //
593 OBJECTHANDLE CLRException::GetPreallocatedHandleForObject(OBJECTREF o)
594 {
595     CONTRACTL
596     {
597         NOTHROW;
598         GC_NOTRIGGER;
599         MODE_COOPERATIVE;
600         FORBID_FAULT;
601     }
602     CONTRACTL_END;
603     
604     if (o == ObjectFromHandle(g_pPreallocatedBaseException))
605     {
606         return g_pPreallocatedBaseException;                    
607     }
608     else if (o == ObjectFromHandle(g_pPreallocatedOutOfMemoryException))
609     {
610         return g_pPreallocatedOutOfMemoryException;
611     }
612     else if (o == ObjectFromHandle(g_pPreallocatedStackOverflowException))
613     {
614         return g_pPreallocatedStackOverflowException;
615     }
616     else if (o == ObjectFromHandle(g_pPreallocatedExecutionEngineException))
617     {
618         return g_pPreallocatedExecutionEngineException;
619     }
620     else if (o == ObjectFromHandle(g_pPreallocatedThreadAbortException))
621     {
622         return g_pPreallocatedThreadAbortException;
623     }
624
625     // The preallocated rude thread abort exception is not always preallocated.
626     if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
627         (o == ObjectFromHandle(g_pPreallocatedRudeThreadAbortException)))
628     {
629         return g_pPreallocatedRudeThreadAbortException;
630     }
631
632     return NULL;
633 }
634
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()
637 {
638     CONTRACTL
639     {
640         NOTHROW;
641         MODE_COOPERATIVE;
642     }
643     CONTRACTL_END;
644
645     OBJECTREF retVal = NULL;
646
647     EX_TRY
648     {
649         FAULT_NOT_FATAL();
650
651         EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
652         pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
653         pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
654
655         retVal = pOutOfMemory;
656     }
657     EX_CATCH
658     {
659         retVal = GetPreallocatedOutOfMemoryException();
660     }
661     EX_END_CATCH(SwallowAllExceptions)
662
663     _ASSERTE(retVal != NULL);
664
665     return retVal;
666 }
667
668
669 // Works on non-CLRExceptions as well
670 // static function
671 OBJECTREF CLRException::GetThrowableFromException(Exception *pException)
672 {
673     CONTRACTL
674     {
675         GC_TRIGGERS;
676         NOTHROW;
677         MODE_COOPERATIVE;
678     }
679     CONTRACTL_END;
680
681     Thread* pThread = GetThread();
682
683     // Can't have a throwable without a Thread.
684     _ASSERTE(pThread != NULL);
685
686     if (NULL == pException)
687     {
688         return pThread->LastThrownObject();
689     }
690
691     if (pException->IsType(CLRException::GetType()))
692         return ((CLRException*)pException)->GetThrowable();
693
694     if (pException->IsType(EEException::GetType()))
695         return ((EEException*)pException)->GetThrowable();
696
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.
701
702     if (pException->IsType(SEHException::GetType()))
703     {
704         SEHException *pSEHException = (SEHException*)pException;
705
706         switch (pSEHException->m_exception.ExceptionCode)
707         {
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)))
714             {
715                 return pThread->LastThrownObject();
716             }
717             else
718             {
719                 break;
720             }
721
722         case STATUS_NO_MEMORY:
723             return GetBestOutOfMemoryException();
724
725         case STATUS_STACK_OVERFLOW:
726             return GetPreallocatedStackOverflowException();
727         }
728
729         DWORD exceptionCode = 
730           MapWin32FaultToCOMPlusException(&pSEHException->m_exception);
731
732         EEException e((RuntimeExceptionKind)exceptionCode);
733
734         OBJECTREF throwable = e.GetThrowable();
735         GCPROTECT_BEGIN (throwable);
736         EX_TRY
737         {
738             SCAN_IGNORE_FAULT;
739             if (throwable != NULL  && !CLRException::IsPreallocatedExceptionObject(throwable))
740             {
741                 _ASSERTE(IsException(throwable->GetMethodTable()));
742
743                 // set the exception code
744                 ((EXCEPTIONREF)throwable)->SetXCode(pSEHException->m_exception.ExceptionCode);
745             }
746         }
747         EX_CATCH
748         {
749         }
750         EX_END_CATCH(SwallowAllExceptions)
751         GCPROTECT_END ();
752             
753         return throwable;
754     }
755     else
756     {
757         // We can enter here for HRException, COMException, DelegatingException
758         // just to name a few.
759         OBJECTREF oRetVal = NULL;
760         GCPROTECT_BEGIN(oRetVal);
761         {
762             EX_TRY
763             {
764                 HRESULT hr = pException->GetHR();
765
766                 if (hr == E_OUTOFMEMORY || hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY))
767                 {
768                     oRetVal = GetBestOutOfMemoryException();
769                 }
770                 else if (hr == COR_E_STACKOVERFLOW)
771                 {
772                     oRetVal = GetPreallocatedStackOverflowException();
773                 }
774                 else
775                 {
776                     SafeComHolder<IErrorInfo> pErrInfo(pException->GetErrorInfo());
777
778                     if (pErrInfo != NULL)
779                     {
780                         GetExceptionForHR(hr, pErrInfo, &oRetVal);
781                     }
782                     else
783                     {
784                         SString message;
785                         pException->GetMessage(message);
786
787                         EEMessageException e(hr, IDS_EE_GENERIC, message);
788
789                         oRetVal = e.CreateThrowable();
790                     }
791                 }
792             }
793             EX_CATCH
794             {
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.
799
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();
805
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");
809                     if (oRetVal == NULL)
810                         oRetVal = GetPreallocatedOutOfMemoryException();
811                 }
812                 else
813                 if (pNewException->IsType(CLRLastThrownObjectException::GetType()) &&
814                     (pThread->LastThrownObject() != NULL))           
815                 {
816                     STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: LTO Exception creating throwable; getting LastThrownObject.\n");
817                     if (oRetVal == NULL)
818                         oRetVal = pThread->LastThrownObject();
819                 }
820                 else
821                 {   
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.
825                     //
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.
829                     //
830                     // Hence, we return preallocated System.Exception instance.
831                     if (oRetVal == NULL)
832                     {
833                         oRetVal = GetPreallocatedBaseException();
834                         STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: Unknown Exception creating throwable; getting preallocated System.Exception.\n");
835                     }
836                 }
837
838             }
839             EX_END_CATCH(SwallowAllExceptions)
840         }
841         GCPROTECT_END();
842
843         return oRetVal;
844     }
845 } // OBJECTREF CLRException::GetThrowableFromException()
846
847 OBJECTREF CLRException::GetThrowableFromExceptionRecord(EXCEPTION_RECORD *pExceptionRecord)
848 {
849     CONTRACTL
850     {
851         GC_NOTRIGGER;
852         NOTHROW;
853         MODE_ANY;
854     }
855     CONTRACTL_END;
856
857     if (IsComPlusException(pExceptionRecord))
858     {
859         return GetThread()->LastThrownObject();
860     }
861
862     return NULL;
863 }
864
865 void CLRException::HandlerState::CleanupTry()
866 {
867     STATIC_CONTRACT_NOTHROW;
868     STATIC_CONTRACT_GC_NOTRIGGER;
869     STATIC_CONTRACT_MODE_ANY;
870
871     if (m_pThread != NULL)
872     {
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);
878
879         if (m_fPreemptiveGCDisabled != m_pThread->PreemptiveGCDisabled())
880         {
881             if (m_fPreemptiveGCDisabled)
882                 m_pThread->DisablePreemptiveGC();
883             else
884                 m_pThread->EnablePreemptiveGC();
885         }
886         END_GETTHREAD_ALLOWED;
887     }
888
889     // Make sure to call the base class's CleanupTry so it can do whatever it wants to do.
890     Exception::HandlerState::CleanupTry();
891 }
892
893 void CLRException::HandlerState::SetupCatch(INDEBUG_COMMA(__in_z const char * szFile) int lineNum)
894 {
895     STATIC_CONTRACT_NOTHROW;
896     STATIC_CONTRACT_GC_NOTRIGGER;
897     STATIC_CONTRACT_MODE_ANY;
898     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
899
900     Exception::HandlerState::SetupCatch(INDEBUG_COMMA(szFile) lineNum);
901
902     Thread *pThread = NULL;
903     DWORD exceptionCode = 0;
904
905     if (g_fEEStarted)
906     {
907         pThread = GetThread();
908         exceptionCode = GetCurrentExceptionCode();
909     }
910     
911     if (!DidCatchCxx())
912     {
913         if (exceptionCode == STATUS_STACK_OVERFLOW)
914         {
915             // Handle SO exception
916             // 
917             // We should ensure that a valid Thread object exists before trying to set SO as the LTO.
918             if (pThread != NULL)
919             {
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.
923                 GCX_COOP();
924                 pThread->SetSOForLastThrownObject();
925             }
926
927             if (exceptionCode == STATUS_STACK_OVERFLOW)
928             {
929                 // We have called HandleStackOverflow for soft SO through our vectored exception handler.
930                 EEPolicy::HandleStackOverflow(SOD_UnmanagedFrameHandler, FRAME_TOP);                
931             }
932         }
933     }
934
935 #ifdef WIN64EXCEPTIONS
936     if (!DidCatchCxx())
937     {
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);
942     }
943 #endif // WIN64EXCEPTIONS
944 }
945
946 #ifdef LOGGING
947 void CLRException::HandlerState::SucceedCatch()
948 {
949     STATIC_CONTRACT_NOTHROW;
950     STATIC_CONTRACT_GC_NOTRIGGER;
951     STATIC_CONTRACT_MODE_ANY;
952     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
953
954     LOG((LF_EH, LL_INFO100, "EX_CATCH catch succeeded (CLRException::HandlerState)\n"));
955
956     //
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.
964     //
965     //
966
967     Exception::HandlerState::SucceedCatch();
968 }
969 #endif
970
971 #endif // CROSSGEN_COMPILE
972
973 // ---------------------------------------------------------------------------
974 // EEException methods
975 // ---------------------------------------------------------------------------
976
977 //------------------------------------------------------------------------
978 // Array that is used to retrieve the right exception for a given HRESULT.
979 //------------------------------------------------------------------------
980
981 #ifdef FEATURE_COMINTEROP
982
983 struct WinRtHR_to_ExceptionKind_Map
984 {
985     RuntimeExceptionKind reKind;
986     int cHRs;
987     const HRESULT *aHRs;
988 };
989
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, ...)
994 #include "rexcep.h"
995 kWinRtExLastException
996 };
997
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, ...)
1001 #include "rexcep.h"
1002
1003 static const
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, ...)
1008 #include "rexcep.h"
1009 };
1010
1011 #endif  // FEATURE_COMINTEROP
1012
1013 struct ExceptionHRInfo
1014 {
1015     int cHRs;
1016     const HRESULT *aHRs;
1017 };
1018
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__)
1022 #include "rexcep.h"
1023
1024 static const
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__)
1029 #include "rexcep.h"
1030 };
1031
1032
1033 static const
1034 bool gShouldDisplayHR[] =
1035 {   
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__)
1039 #include "rexcep.h"
1040 };
1041
1042
1043 /*static*/
1044 HRESULT EEException::GetHRFromKind(RuntimeExceptionKind reKind)
1045 {
1046     LIMITED_METHOD_CONTRACT;
1047     return gExceptionHRInfos[reKind].aHRs[0];
1048 }
1049
1050 HRESULT EEException::GetHR() 
1051
1052     LIMITED_METHOD_CONTRACT;
1053
1054     return EEException::GetHRFromKind(m_kind);
1055 }
1056     
1057 IErrorInfo *EEException::GetErrorInfo()
1058 {
1059     LIMITED_METHOD_CONTRACT;
1060     
1061     return NULL;
1062 }
1063
1064 BOOL EEException::GetThrowableMessage(SString &result)
1065 {
1066     CONTRACTL
1067     {
1068         GC_TRIGGERS;
1069         THROWS;
1070         MODE_ANY;
1071     }
1072     CONTRACTL_END;
1073
1074     // Return a meaningful HR message, if there is one.
1075
1076     HRESULT hr = GetHR();
1077
1078     // If the hr is more interesting than the kind, use that
1079     // for a message.
1080
1081     if (hr != S_OK 
1082         && hr != E_FAIL
1083         && (gShouldDisplayHR[m_kind]
1084             || gExceptionHRInfos[m_kind].aHRs[0] !=  hr))
1085     {
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);
1089         
1090         GenerateTopLevelHRExceptionMessage(hr, result);
1091         return TRUE;
1092     }
1093
1094     // No interesting hr - just keep the class default message.
1095
1096     return FALSE;
1097 }
1098
1099 void EEException::GetMessage(SString &result)
1100 {
1101     CONTRACTL
1102     {
1103         GC_TRIGGERS;
1104         THROWS;
1105         MODE_ANY;
1106     }
1107     CONTRACTL_END;
1108
1109     // First look for a specialized message
1110     if (GetThrowableMessage(result))
1111         return;
1112     
1113     // Otherwise, report the class's generic message
1114     LPCUTF8 pszExceptionName = NULL;
1115     if (m_kind <= kLastExceptionInMscorlib)
1116     {
1117         pszExceptionName = MscorlibBinder::GetExceptionName(m_kind);
1118         result.SetUTF8(pszExceptionName);
1119     }
1120 #ifndef CROSSGEN_COMPILE
1121     else
1122     {
1123         FrameworkExceptionLoader::GetExceptionName(m_kind, result);
1124     }
1125 #endif // CROSSGEN_COMPILE
1126 }
1127
1128 OBJECTREF EEException::CreateThrowable()
1129 {
1130 #ifdef CROSSGEN_COMPILE
1131     _ASSERTE(false);
1132     return NULL;
1133 #else
1134     CONTRACTL
1135     {
1136         GC_TRIGGERS;
1137         THROWS;
1138         MODE_COOPERATIVE;
1139     }
1140     CONTRACTL_END;
1141
1142     _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
1143     static int allocCount = 0;
1144
1145     MethodTable *pMT = NULL;
1146     if (m_kind <= kLastExceptionInMscorlib)
1147         pMT = MscorlibBinder::GetException(m_kind);
1148     else
1149     {
1150         pMT = FrameworkExceptionLoader::GetException(m_kind);
1151     }
1152
1153     ThreadPreventAsyncHolder preventAsyncHolder(m_kind == kThreadAbortException);
1154
1155     OBJECTREF throwable = AllocateObject(pMT);
1156     allocCount++;
1157     GCPROTECT_BEGIN(throwable);
1158
1159     {
1160         ThreadPreventAsyncHolder preventAbort(m_kind == kThreadAbortException ||
1161                                               m_kind == kThreadInterruptedException);
1162         CallDefaultConstructor(throwable);
1163     }
1164
1165     HRESULT hr = GetHR();
1166     ((EXCEPTIONREF)throwable)->SetHResult(hr);
1167
1168     SString message;
1169     if (GetThrowableMessage(message))
1170     {
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.
1174         //
1175         // We only want to replace whatever the default constructor put there, if we
1176         // have something meaningful to add.
1177         
1178         STRINGREF s = StringObject::NewString(message);
1179         ((EXCEPTIONREF)throwable)->SetMessage(s);
1180     }
1181
1182     GCPROTECT_END();
1183
1184     return throwable;
1185 #endif
1186 }
1187
1188 RuntimeExceptionKind EEException::GetKindFromHR(HRESULT hr, bool fIsWinRtMode /*= false*/)
1189 {
1190     LIMITED_METHOD_CONTRACT;
1191
1192     #ifdef FEATURE_COMINTEROP    
1193     // If we are in WinRT mode, try to get a WinRT specific mapping first:
1194     if (fIsWinRtMode)
1195     {
1196         for (int i = 0; i < kWinRtExLastException; i++)
1197         {
1198             for (int j = 0; j < gWinRtHR_to_ExceptionKind_Maps[i].cHRs; j++)
1199             {
1200                 if (gWinRtHR_to_ExceptionKind_Maps[i].aHRs[j] == hr)
1201                 {
1202                     return gWinRtHR_to_ExceptionKind_Maps[i].reKind;                    
1203                 }
1204             }
1205         }
1206     }    
1207     #endif  // FEATURE_COMINTEROP
1208     
1209     // Is not in WinRT mode OR did not find a WinRT specific mapping. Check normal mappings:
1210     
1211     for (int i = 0; i < kLastException; i++)
1212     {
1213         for (int j = 0; j < gExceptionHRInfos[i].cHRs; j++)
1214         {
1215             if (gExceptionHRInfos[i].aHRs[j] == hr)
1216                 return (RuntimeExceptionKind) i;
1217         }
1218     }
1219
1220     return (fIsWinRtMode ? kException : kCOMException);
1221     
1222 } // RuntimeExceptionKind EEException::GetKindFromHR()
1223
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)
1228 {
1229     CONTRACTL
1230     {
1231         GC_TRIGGERS;
1232         THROWS;
1233         MODE_ANY;
1234     }
1235     CONTRACTL_END;
1236
1237     BOOL ok;
1238
1239     StackSString temp;
1240     ok = temp.LoadResource(CCompRC::Error, iResourceID);
1241
1242     if (ok)
1243         result.FormatMessage(FORMAT_MESSAGE_FROM_STRING,
1244          (LPCWSTR)temp, 0, 0, arg1, arg2, arg3, arg4, arg5, arg6);
1245
1246     return ok;
1247 }
1248
1249 // ---------------------------------------------------------------------------
1250 // EEMessageException methods
1251 // ---------------------------------------------------------------------------
1252
1253 HRESULT EEMessageException::GetHR()
1254 {
1255     WRAPPER_NO_CONTRACT;
1256     
1257     return m_hr;
1258 }
1259
1260 BOOL EEMessageException::GetThrowableMessage(SString &result)
1261 {
1262     CONTRACTL
1263     {
1264         GC_TRIGGERS;
1265         THROWS;
1266         MODE_ANY;
1267     }
1268     CONTRACTL_END;
1269
1270     if (m_resID != 0 && GetResourceMessage(m_resID, result))
1271         return TRUE;
1272
1273     return EEException::GetThrowableMessage(result);
1274 }
1275
1276 BOOL EEMessageException::GetResourceMessage(UINT iResourceID, SString &result)
1277 {
1278     WRAPPER_NO_CONTRACT;
1279
1280     return EEException::GetResourceMessage(
1281         iResourceID, result, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6);
1282 }
1283
1284 // ---------------------------------------------------------------------------
1285 // EEResourceException methods
1286 // ---------------------------------------------------------------------------
1287
1288 void EEResourceException::GetMessage(SString &result)
1289 {
1290     WRAPPER_NO_CONTRACT; 
1291     // 
1292     // Return a simplified message, 
1293     // since we don't want to call managed code here.
1294     //
1295
1296     result.Printf("%s (message resource %s)", 
1297                   MscorlibBinder::GetExceptionName(m_kind), m_resourceName.GetUnicode());
1298 }
1299
1300 BOOL EEResourceException::GetThrowableMessage(SString &result)
1301 {
1302     CONTRACTL
1303     {
1304         GC_TRIGGERS;
1305         THROWS;
1306         MODE_COOPERATIVE;
1307     }
1308     CONTRACTL_END;
1309
1310 #ifndef CROSSGEN_COMPILE
1311     STRINGREF message = NULL;
1312     ResMgrGetString(m_resourceName, &message);
1313
1314     if (message != NULL) 
1315     {
1316         message->GetSString(result);
1317         return TRUE;
1318     }
1319 #endif // CROSSGEN_COMPILE
1320
1321     return EEException::GetThrowableMessage(result);
1322 }
1323
1324 // ---------------------------------------------------------------------------
1325 // EEFieldException is an EE exception subclass composed of a field
1326 // ---------------------------------------------------------------------------
1327
1328     
1329 BOOL EEFieldException::GetThrowableMessage(SString &result)
1330 {
1331     CONTRACTL
1332     {
1333         GC_TRIGGERS;
1334         THROWS;
1335         MODE_ANY;
1336     }
1337     CONTRACTL_END;
1338
1339     if (m_messageID == 0)
1340     {
1341         LPUTF8 szFullName;
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);
1348
1349         return TRUE;
1350     }
1351     else
1352     {
1353         _ASSERTE(m_pAccessingMD != NULL);
1354
1355         const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1356             TypeString::FormatNamespace |
1357             TypeString::FormatAngleBrackets |
1358             TypeString::FormatSignature);
1359
1360         StackSString caller;
1361         TypeString::AppendMethod(caller,
1362                                  m_pAccessingMD,
1363                                  m_pAccessingMD->GetClassInstantiation(),
1364                                  formatFlags);
1365
1366         StackSString field;
1367         TypeString::AppendField(field,
1368                                 m_pFD,
1369                                 m_pFD->GetApproxEnclosingMethodTable()->GetInstantiation(),
1370                                 formatFlags);
1371
1372         return GetResourceMessage(m_messageID, result, caller, field, m_additionalContext);
1373     }
1374 }
1375
1376 // ---------------------------------------------------------------------------
1377 // EEMethodException is an EE exception subclass composed of a field
1378 // ---------------------------------------------------------------------------
1379
1380 BOOL EEMethodException::GetThrowableMessage(SString &result)
1381 {
1382     CONTRACTL
1383     {
1384         GC_TRIGGERS;
1385         THROWS;
1386         MODE_ANY;
1387     }
1388     CONTRACTL_END;
1389
1390     if (m_messageID == 0)
1391     {
1392         LPUTF8 szFullName;
1393         LPCUTF8 szClassName, szMember;
1394         szMember = m_pMD->GetName();
1395         DefineFullyQualifiedNameForClass();
1396         szClassName = GetFullyQualifiedNameForClass(m_pMD->GetMethodTable());
1397         //@todo GENERICS: exact instantiations?
1398         MetaSig tmp(m_pMD);
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);
1403
1404         return TRUE;
1405     }
1406     else
1407     {
1408         _ASSERTE(m_pAccessingMD != NULL);
1409
1410         const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1411             TypeString::FormatNamespace |
1412             TypeString::FormatAngleBrackets |
1413             TypeString::FormatSignature);
1414
1415         StackSString caller;
1416         TypeString::AppendMethod(caller,
1417                                  m_pAccessingMD,
1418                                  m_pAccessingMD->GetClassInstantiation(),
1419                                  formatFlags);
1420
1421         StackSString callee;
1422         TypeString::AppendMethod(callee,
1423                                  m_pMD,
1424                                  m_pMD->GetClassInstantiation(),
1425                                  formatFlags);
1426
1427         return GetResourceMessage(m_messageID, result, caller, callee, m_additionalContext);
1428     }
1429 }
1430
1431 BOOL EETypeAccessException::GetThrowableMessage(SString &result)
1432 {
1433     CONTRACTL
1434     {
1435         GC_TRIGGERS;
1436         THROWS;
1437         MODE_ANY;
1438     }
1439     CONTRACTL_END;
1440
1441     const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1442             TypeString::FormatNamespace |
1443             TypeString::FormatAngleBrackets |
1444             TypeString::FormatSignature);
1445     StackSString type;
1446     TypeString::AppendType(type, TypeHandle(m_pMT), formatFlags);
1447
1448     if (m_messageID == 0)
1449     {
1450         result.Set(type);
1451         return TRUE;
1452     }
1453     else
1454     {
1455         _ASSERTE(m_pAccessingMD != NULL);
1456
1457         StackSString caller;
1458         TypeString::AppendMethod(caller,
1459                                  m_pAccessingMD,
1460                                  m_pAccessingMD->GetClassInstantiation(),
1461                                  formatFlags);
1462
1463         return GetResourceMessage(m_messageID, result, caller, type, m_additionalContext);
1464     }
1465 }
1466
1467 // ---------------------------------------------------------------------------
1468 // EEArgumentException is an EE exception subclass representing a bad argument
1469 // ---------------------------------------------------------------------------
1470
1471 typedef struct {
1472     OBJECTREF pThrowable;
1473     STRINGREF s1;
1474     OBJECTREF pTmpThrowable;
1475 } ProtectArgsStruct;
1476
1477 OBJECTREF EEArgumentException::CreateThrowable()
1478 {
1479 #ifdef CROSSGEN_COMPILE
1480     _ASSERTE(false);
1481     return NULL;
1482 #else
1483
1484     CONTRACTL
1485     {
1486         GC_TRIGGERS;
1487         THROWS;
1488         MODE_COOPERATIVE;
1489     }
1490     CONTRACTL_END;
1491
1492     _ASSERTE(GetThread() != NULL);
1493
1494     ProtectArgsStruct prot;
1495     memset(&prot, 0, sizeof(ProtectArgsStruct));
1496     ResMgrGetString(m_resourceName, &prot.s1);
1497     GCPROTECT_BEGIN(prot);
1498
1499     MethodTable *pMT = MscorlibBinder::GetException(m_kind);
1500     prot.pThrowable = AllocateObject(pMT);
1501
1502     MethodDesc* pMD = MemberLoader::FindMethod(prot.pThrowable->GetMethodTable(),
1503                             COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_RetVoid);
1504
1505     if (!pMD)
1506     {
1507         MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1508         COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1509     }
1510
1511     MethodDescCallSite exceptionCtor(pMD);
1512
1513     STRINGREF argName = StringObject::NewString(m_argumentName);
1514
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)
1518     {
1519         ARG_SLOT args1[] = { 
1520             ObjToArgSlot(prot.pThrowable),
1521             ObjToArgSlot(prot.s1),
1522             ObjToArgSlot(argName),
1523         };
1524         exceptionCtor.Call(args1);
1525     }
1526     else
1527     {
1528         ARG_SLOT args1[] = { 
1529             ObjToArgSlot(prot.pThrowable),
1530             ObjToArgSlot(argName),
1531             ObjToArgSlot(prot.s1),
1532         };
1533         exceptionCtor.Call(args1);
1534     }
1535
1536     GCPROTECT_END(); //Prot
1537
1538     return prot.pThrowable;
1539 #endif
1540 }
1541
1542
1543 // ---------------------------------------------------------------------------
1544 // EETypeLoadException is an EE exception subclass representing a type loading
1545 // error
1546 // ---------------------------------------------------------------------------
1547
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)
1554 {
1555     CONTRACTL
1556     {
1557         GC_NOTRIGGER;
1558         THROWS;
1559         MODE_ANY;
1560     }
1561     CONTRACTL_END;
1562
1563     if(pszNameSpace)
1564     {
1565         SString sNameSpace(SString::Utf8, pszNameSpace);
1566         SString sTypeName(SString::Utf8, pTypeName);
1567         m_fullName.MakeFullNamespacePath(sNameSpace, sTypeName);
1568     }
1569     else if (pTypeName)
1570         m_fullName.SetUTF8(pTypeName);
1571     else {
1572         WCHAR wszTemplate[30];
1573         if (FAILED(UtilLoadStringRC(IDS_EE_NAME_UNKNOWN,
1574                                     wszTemplate,
1575                                     sizeof(wszTemplate)/sizeof(wszTemplate[0]),
1576                                     FALSE)))
1577             wszTemplate[0] = W('\0');
1578         MAKE_UTF8PTR_FROMWIDE(name, wszTemplate);
1579         m_fullName.SetUTF8(name);
1580     }
1581 }
1582
1583 EETypeLoadException::EETypeLoadException(LPCWSTR pFullName,
1584                                          LPCWSTR pAssemblyName, 
1585                                          LPCUTF8 pMessageArg, 
1586                                          UINT resIDWhy)
1587   : EEException(kTypeLoadException),
1588     m_pAssemblyName(pAssemblyName),
1589     m_pMessageArg(SString::Utf8, pMessageArg),
1590     m_resIDWhy(resIDWhy)
1591 {
1592     CONTRACTL
1593     {
1594         GC_NOTRIGGER;
1595         THROWS;
1596         MODE_ANY;
1597     }
1598     CONTRACTL_END;
1599
1600     MAKE_UTF8PTR_FROMWIDE(name, pFullName);
1601     m_fullName.SetUTF8(name);
1602 }
1603
1604 void EETypeLoadException::GetMessage(SString &result)
1605 {
1606     WRAPPER_NO_CONTRACT;
1607     GetResourceMessage(IDS_CLASSLOAD_GENERAL, result,
1608                        m_fullName, m_pAssemblyName, m_pMessageArg); 
1609 }
1610
1611 OBJECTREF EETypeLoadException::CreateThrowable()
1612 {
1613 #ifdef CROSSGEN_COMPILE
1614     _ASSERTE(false);
1615     return NULL;
1616 #else
1617
1618     CONTRACTL
1619     {
1620         GC_TRIGGERS;
1621         THROWS;
1622         MODE_COOPERATIVE;
1623     }
1624     CONTRACTL_END;
1625
1626     MethodTable *pMT = MscorlibBinder::GetException(kTypeLoadException);
1627
1628     struct _gc {
1629         OBJECTREF pNewException;
1630         STRINGREF pNewAssemblyString;
1631         STRINGREF pNewClassString;
1632         STRINGREF pNewMessageArgString;
1633     } gc;
1634     ZeroMemory(&gc, sizeof(gc));
1635     GCPROTECT_BEGIN(gc);
1636
1637     gc.pNewClassString = StringObject::NewString(m_fullName);
1638
1639     if (!m_pMessageArg.IsEmpty())
1640         gc.pNewMessageArgString = StringObject::NewString(m_pMessageArg);
1641
1642     if (!m_pAssemblyName.IsEmpty())
1643         gc.pNewAssemblyString = StringObject::NewString(m_pAssemblyName);
1644
1645     gc.pNewException = AllocateObject(pMT);
1646
1647     MethodDesc* pMD = MemberLoader::FindMethod(gc.pNewException->GetMethodTable(),
1648                             COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_Str_Int_RetVoid);
1649
1650     if (!pMD)
1651     {
1652         MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1653         COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1654     }
1655
1656     MethodDescCallSite exceptionCtor(pMD);
1657
1658     ARG_SLOT args[] = {
1659         ObjToArgSlot(gc.pNewException),
1660         ObjToArgSlot(gc.pNewClassString),
1661         ObjToArgSlot(gc.pNewAssemblyString),
1662         ObjToArgSlot(gc.pNewMessageArgString),
1663         (ARG_SLOT)m_resIDWhy,
1664     };
1665     
1666     exceptionCtor.Call(args);
1667
1668     GCPROTECT_END();
1669         
1670     return gc.pNewException;
1671 #endif
1672 }
1673
1674 // ---------------------------------------------------------------------------
1675 // EEFileLoadException is an EE exception subclass representing a file loading
1676 // error
1677 // ---------------------------------------------------------------------------
1678 EEFileLoadException::EEFileLoadException(const SString &name, HRESULT hr, void *pFusionLog, Exception *pInnerException/* = NULL*/)
1679   : EEException(GetFileLoadKind(hr)),
1680     m_name(name),
1681     m_pFusionLog(pFusionLog),
1682     m_hr(hr)
1683 {
1684     CONTRACTL
1685     {
1686         GC_NOTRIGGER;
1687         THROWS;
1688         MODE_ANY;
1689     }
1690     CONTRACTL_END;
1691
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;
1696
1697     if (m_name.IsEmpty())
1698     {
1699         WCHAR wszTemplate[30];
1700         if (FAILED(UtilLoadStringRC(IDS_EE_NAME_UNKNOWN,
1701                                     wszTemplate,
1702                                     sizeof(wszTemplate)/sizeof(wszTemplate[0]),
1703                                     FALSE)))
1704         {
1705             wszTemplate[0] = W('\0');
1706         }
1707
1708         m_name.Set(wszTemplate);
1709     }
1710 }
1711
1712
1713 EEFileLoadException::~EEFileLoadException()
1714 {
1715     STATIC_CONTRACT_NOTHROW;
1716     STATIC_CONTRACT_GC_NOTRIGGER;
1717
1718 }
1719
1720
1721
1722 void EEFileLoadException::SetFileName(const SString &fileName, BOOL removePath)
1723 {
1724     CONTRACTL
1725     {
1726         GC_NOTRIGGER;
1727         THROWS;
1728         MODE_ANY;
1729     }
1730     CONTRACTL_END;
1731
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>
1734     if (removePath)
1735     {
1736         SString::CIterator i = fileName.End();
1737         
1738         if (fileName.FindBack(i, W('\\')))
1739             i++;
1740
1741         if (fileName.FindBack(i, W('/')))
1742             i++;
1743
1744         m_name.Set(fileName, i, fileName.End());
1745     }
1746     else
1747         m_name.Set(fileName);
1748 }
1749
1750 void EEFileLoadException::GetMessage(SString &result)
1751 {
1752     WRAPPER_NO_CONTRACT;
1753
1754     SString sHR;
1755     GetHRMsg(m_hr, sHR);
1756     GetResourceMessage(GetResourceIDForFileLoadExceptionHR(m_hr), result, m_name, sHR);
1757 }
1758
1759 void EEFileLoadException::GetName(SString &result)
1760 {
1761     WRAPPER_NO_CONTRACT;
1762
1763     result.Set(m_name);
1764 }
1765
1766 /* static */
1767 RuntimeExceptionKind EEFileLoadException::GetFileLoadKind(HRESULT hr)
1768 {
1769     CONTRACTL
1770     {
1771         GC_NOTRIGGER;
1772         NOTHROW;
1773         MODE_ANY;
1774     }
1775     CONTRACTL_END;
1776     
1777     if (Assembly::FileNotFound(hr))
1778         return kFileNotFoundException;
1779     else
1780     {
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;
1800         else 
1801         {
1802             if ((hr == E_OUTOFMEMORY) || (hr == NTE_NO_MEMORY))
1803                 return kOutOfMemoryException;
1804             else
1805                 return kFileLoadException;
1806         }
1807     }
1808 }
1809
1810 OBJECTREF EEFileLoadException::CreateThrowable()
1811 {
1812 #ifdef CROSSGEN_COMPILE
1813     _ASSERTE(false);
1814     return NULL;
1815 #else
1816
1817     CONTRACTL
1818     {
1819         GC_TRIGGERS;
1820         THROWS;
1821         MODE_COOPERATIVE;
1822     }
1823     CONTRACTL_END;
1824
1825     // Fetch any log info from the fusion log
1826     SString logText;
1827     struct _gc {
1828         OBJECTREF pNewException;
1829         STRINGREF pNewFileString;
1830         STRINGREF pFusLogString;
1831     } gc;
1832     ZeroMemory(&gc, sizeof(gc));
1833     GCPROTECT_BEGIN(gc);
1834
1835     gc.pNewFileString = StringObject::NewString(m_name);
1836     gc.pFusLogString = StringObject::NewString(logText);
1837     gc.pNewException = AllocateObject(MscorlibBinder::GetException(m_kind));
1838
1839     MethodDesc* pMD = MemberLoader::FindMethod(gc.pNewException->GetMethodTable(),
1840                             COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_Int_RetVoid);
1841
1842     if (!pMD)
1843     {
1844         MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1845         COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1846     }
1847
1848     MethodDescCallSite  exceptionCtor(pMD);
1849
1850     ARG_SLOT args[] = {
1851         ObjToArgSlot(gc.pNewException),
1852         ObjToArgSlot(gc.pNewFileString),
1853         ObjToArgSlot(gc.pFusLogString),
1854         (ARG_SLOT) m_hr
1855     };
1856
1857     exceptionCtor.Call(args);
1858
1859     GCPROTECT_END();
1860
1861     return gc.pNewException;
1862 #endif
1863 }
1864
1865
1866 /* static */
1867 BOOL EEFileLoadException::CheckType(Exception* ex)
1868 {
1869     LIMITED_METHOD_CONTRACT;
1870
1871     // used as typeof(EEFileLoadException)
1872     RuntimeExceptionKind kind = kException;
1873     if (ex->IsType(EEException::GetType()))
1874         kind=((EEException*)ex)->m_kind;
1875  
1876     
1877     switch(kind)
1878     {
1879         case kFileLoadException:
1880         case kFileNotFoundException:
1881         case kBadImageFormatException:
1882             return TRUE;
1883         default:
1884             return FALSE;
1885     }
1886 };
1887
1888
1889 // <TODO>@todo: ideally we would use inner exceptions with these routines</TODO>
1890
1891 /* static */
1892
1893 /* static */
1894 void DECLSPEC_NORETURN EEFileLoadException::Throw(AssemblySpec  *pSpec, HRESULT hr, Exception *pInnerException/* = NULL*/)
1895 {
1896     CONTRACTL
1897     {
1898         GC_TRIGGERS;
1899         THROWS;
1900         MODE_ANY;
1901     }
1902     CONTRACTL_END;
1903     
1904     if (hr == COR_E_THREADABORTED)
1905         COMPlusThrow(kThreadAbortException);
1906     if (hr == E_OUTOFMEMORY)
1907         COMPlusThrowOM();
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);
1912     }
1913 #endif //FEATURE_COMINTEROP
1914     
1915     StackSString name;
1916     pSpec->GetFileOrDisplayName(0, name);
1917     EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1918 }
1919
1920 /* static */
1921 void DECLSPEC_NORETURN EEFileLoadException::Throw(PEFile *pFile, HRESULT hr, Exception *pInnerException /* = NULL*/)
1922 {
1923     CONTRACTL
1924     {
1925         GC_TRIGGERS;
1926         THROWS;
1927         MODE_ANY;
1928     }
1929     CONTRACTL_END;
1930     
1931     if (hr == COR_E_THREADABORTED)
1932         COMPlusThrow(kThreadAbortException);
1933     if (hr == E_OUTOFMEMORY)
1934         COMPlusThrowOM();
1935
1936     StackSString name;
1937
1938     if (pFile->IsAssembly())
1939         ((PEAssembly*)pFile)->GetDisplayName(name);
1940     else
1941         name = StackSString(SString::Utf8, pFile->GetSimpleName());
1942     EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1943
1944 }
1945
1946 /* static */
1947 void DECLSPEC_NORETURN EEFileLoadException::Throw(LPCWSTR path, HRESULT hr, Exception *pInnerException/* = NULL*/)
1948 {
1949     CONTRACTL
1950     {
1951         GC_TRIGGERS;
1952         THROWS;
1953         MODE_ANY;
1954     }
1955     CONTRACTL_END;
1956     
1957     if (hr == COR_E_THREADABORTED)
1958         COMPlusThrow(kThreadAbortException);
1959     if (hr == E_OUTOFMEMORY)
1960         COMPlusThrowOM();
1961
1962     EX_THROW_WITH_INNER(EEFileLoadException, (StackSString(path), hr), pInnerException);
1963 }
1964
1965 /* static */
1966 /* static */
1967 void DECLSPEC_NORETURN EEFileLoadException::Throw(PEAssembly *parent, 
1968                                                   const void *memory, COUNT_T size, HRESULT hr, Exception *pInnerException/* = NULL*/)
1969 {
1970     CONTRACTL
1971     {
1972         GC_TRIGGERS;
1973         THROWS;
1974         MODE_ANY;
1975     }
1976     CONTRACTL_END;
1977     
1978     if (hr == COR_E_THREADABORTED)
1979         COMPlusThrow(kThreadAbortException);
1980     if (hr == E_OUTOFMEMORY)
1981         COMPlusThrowOM();
1982
1983     StackSString name;
1984     name.Printf("%d bytes loaded from ", size);
1985
1986     StackSString parentName;
1987     parent->GetDisplayName(parentName);
1988
1989     name.Append(parentName);
1990     EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1991 }
1992
1993 #ifndef CROSSGEN_COMPILE
1994 // ---------------------------------------------------------------------------
1995 // EEComException methods
1996 // ---------------------------------------------------------------------------
1997
1998 static HRESULT Undefer(EXCEPINFO *pExcepInfo)
1999 {
2000     CONTRACTL
2001     {
2002         GC_NOTRIGGER;
2003         NOTHROW;
2004         MODE_ANY;
2005     }
2006     CONTRACTL_END;
2007
2008     if (pExcepInfo->pfnDeferredFillIn)
2009     {
2010         EXCEPINFO FilledInExcepInfo; 
2011
2012         HRESULT hr = pExcepInfo->pfnDeferredFillIn(&FilledInExcepInfo);
2013         if (SUCCEEDED(hr))
2014         {
2015             // Free the strings in the original EXCEPINFO.
2016             if (pExcepInfo->bstrDescription)
2017             {
2018                 SysFreeString(pExcepInfo->bstrDescription);
2019                 pExcepInfo->bstrDescription = NULL;
2020             }
2021             if (pExcepInfo->bstrSource)
2022             {
2023                 SysFreeString(pExcepInfo->bstrSource);
2024                 pExcepInfo->bstrSource = NULL;
2025             }
2026             if (pExcepInfo->bstrHelpFile)
2027             {
2028                 SysFreeString(pExcepInfo->bstrHelpFile);
2029                 pExcepInfo->bstrHelpFile = NULL;
2030             }
2031
2032             // Fill in the new data
2033             *pExcepInfo = FilledInExcepInfo;
2034         }
2035     }
2036
2037     if (pExcepInfo->scode != 0)
2038         return pExcepInfo->scode;
2039     else
2040         return (HRESULT)pExcepInfo->wCode;
2041 }
2042
2043 EECOMException::EECOMException(EXCEPINFO *pExcepInfo)
2044   : EEException(GetKindFromHR(Undefer(pExcepInfo)))
2045 {
2046     WRAPPER_NO_CONTRACT;
2047
2048     if (pExcepInfo->scode != 0)
2049         m_ED.hr = pExcepInfo->scode;
2050     else
2051         m_ED.hr = (HRESULT)pExcepInfo->wCode;
2052     
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;
2058
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;
2065 #endif
2066
2067     // Zero the EXCEPINFO.
2068     memset(pExcepInfo, NULL, sizeof(EXCEPINFO));
2069 }
2070
2071 EECOMException::EECOMException(ExceptionData *pData)
2072   : EEException(GetKindFromHR(pData->hr))
2073 {
2074     LIMITED_METHOD_CONTRACT;
2075     
2076     m_ED = *pData;
2077
2078     // Zero the data.
2079     ZeroMemory(pData, sizeof(ExceptionData));
2080 }    
2081
2082 EECOMException::EECOMException(
2083     HRESULT hr,
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))
2090 {
2091     WRAPPER_NO_CONTRACT;
2092     
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
2099
2100     m_ED.hr = hr;
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;
2106
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;
2113 #endif
2114
2115     FillExceptionData(&m_ED, pErrInfo, pRestrictedErrInfo);
2116 }
2117
2118 BOOL EECOMException::GetThrowableMessage(SString &result)
2119 {
2120      CONTRACTL
2121     {
2122         GC_TRIGGERS;
2123         THROWS;
2124         MODE_ANY;
2125     }
2126     CONTRACTL_END;
2127
2128 #ifdef FEATURE_COMINTEROP
2129     if (m_ED.bstrDescription != NULL || m_ED.bstrRestrictedError != NULL)
2130     {
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.
2135
2136         result.Clear();
2137
2138         // If we have a restricted description, start our message with that
2139         if (m_ED.bstrDescription != NULL)
2140         {
2141             SString generalInformation(m_ED.bstrDescription, SysStringLen(m_ED.bstrDescription));
2142             result.Append(generalInformation);
2143
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)
2146             {
2147                 result.Append(W("\r\n"));
2148             }
2149         }
2150
2151         // If we have additional error information, attach it to the end of the string
2152         if (m_ED.bstrRestrictedError != NULL)
2153         {
2154             SString restrictedDescription(m_ED.bstrRestrictedError, SysStringLen(m_ED.bstrRestrictedError));
2155             result.Append(restrictedDescription);
2156         }
2157     }
2158 #else // !FEATURE_COMINTEROP
2159     if (m_ED.bstrDescription != NULL)
2160     {
2161         result.Set(m_ED.bstrDescription, SysStringLen(m_ED.bstrDescription));
2162     }
2163 #endif // FEATURE_COMINTEROP
2164     else
2165     {
2166         GenerateTopLevelHRExceptionMessage(GetHR(), result);
2167     }
2168
2169     return TRUE;
2170 }
2171
2172 EECOMException::~EECOMException()
2173 {
2174     WRAPPER_NO_CONTRACT;
2175     
2176     FreeExceptionData(&m_ED);
2177 }
2178
2179 HRESULT EECOMException::GetHR()
2180 {
2181     LIMITED_METHOD_CONTRACT;
2182     
2183     return m_ED.hr;
2184 }
2185
2186 OBJECTREF EECOMException::CreateThrowable()
2187 {
2188     CONTRACTL
2189     {
2190         GC_TRIGGERS;
2191         THROWS;
2192         MODE_COOPERATIVE;
2193     }
2194     CONTRACTL_END;
2195
2196     OBJECTREF throwable = NULL;
2197     GCPROTECT_BEGIN(throwable);
2198
2199     // Note that this will pick up the message from GetThrowableMessage
2200     throwable = EEException::CreateThrowable();
2201
2202     // Set the _helpURL field in the exception.
2203     if (m_ED.bstrHelpFile) 
2204     {
2205         // Create the help link from the help file and the help context.
2206         STRINGREF helpStr = NULL;
2207         if (m_ED.dwHelpContext != 0)
2208         {
2209             // We have a non 0 help context so use it to form the help link.
2210             SString strMessage;
2211             strMessage.Printf(W("%s#%d"), m_ED.bstrHelpFile, m_ED.dwHelpContext);
2212             helpStr = StringObject::NewString(strMessage);
2213         }
2214         else
2215         {
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));
2218         }
2219
2220         ((EXCEPTIONREF)throwable)->SetHelpURL(helpStr);
2221     } 
2222         
2223     // Set the Source field in the exception.
2224     STRINGREF sourceStr = NULL;
2225     if (m_ED.bstrSource) 
2226     {
2227         sourceStr = StringObject::NewString(m_ED.bstrSource, SysStringLen(m_ED.bstrSource));
2228     }
2229     else
2230     {
2231         // for now set a null source
2232         sourceStr = StringObject::GetEmptyString();
2233     }
2234     ((EXCEPTIONREF)throwable)->SetSource(sourceStr);
2235
2236 #ifdef FEATURE_COMINTEROP
2237     //
2238     // Support for WinRT interface IRestrictedErrorInfo
2239     //
2240     if (m_ED.pRestrictedErrorInfo)
2241     {
2242
2243         struct _gc {
2244             STRINGREF RestrictedErrorRef;
2245             STRINGREF ReferenceRef;
2246             STRINGREF RestrictedCapabilitySidRef;
2247             OBJECTREF RestrictedErrorInfoObjRef;
2248         } gc;
2249         ZeroMemory(&gc, sizeof(gc));
2250     
2251         GCPROTECT_BEGIN(gc);
2252         
2253         EX_TRY
2254         {            
2255             gc.RestrictedErrorRef = StringObject::NewString(
2256                 m_ED.bstrRestrictedError, 
2257                 SysStringLen(m_ED.bstrRestrictedError)
2258                 );
2259             gc.ReferenceRef = StringObject::NewString(
2260                 m_ED.bstrReference, 
2261                 SysStringLen(m_ED.bstrReference)
2262                 );
2263
2264             gc.RestrictedCapabilitySidRef = StringObject::NewString(
2265                 m_ED.bstrCapabilitySid,
2266                 SysStringLen(m_ED.bstrCapabilitySid)
2267                 );
2268
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 *
2273                 NULL,                           // ClassMT
2274                 NULL,                           // ItfMT 
2275                 ObjFromComIP::CLASS_IS_HINT | ObjFromComIP::IGNORE_WINRT_AND_SKIP_UNBOXING
2276                 );
2277
2278             //
2279             // Call Exception.AddExceptionDataForRestrictedErrorInfo and put error information 
2280             // from IRestrictedErrorInfo on Exception.Data
2281             //        
2282             MethodDescCallSite addExceptionDataForRestrictedErrorInfo(
2283                 METHOD__EXCEPTION__ADD_EXCEPTION_DATA_FOR_RESTRICTED_ERROR_INFO,
2284                 &throwable
2285                 );
2286
2287             ARG_SLOT Args[] =
2288             { 
2289                 ObjToArgSlot(throwable),
2290                 ObjToArgSlot(gc.RestrictedErrorRef),
2291                 ObjToArgSlot(gc.ReferenceRef),
2292                 ObjToArgSlot(gc.RestrictedCapabilitySidRef),
2293                 ObjToArgSlot(gc.RestrictedErrorInfoObjRef),
2294                 BoolToArgSlot(m_ED.bHasLanguageRestrictedErrorInfo)
2295             };
2296
2297             addExceptionDataForRestrictedErrorInfo.Call(Args);
2298
2299         }
2300         EX_CATCH
2301         {
2302             // IDictionary.Add may throw. Ignore all non terminal exceptions    
2303         }
2304         EX_END_CATCH(RethrowTerminalExceptions)
2305
2306         GCPROTECT_END();
2307     }
2308 #endif // FEATURE_COMINTEROP
2309
2310     GCPROTECT_END();
2311
2312
2313     return throwable;
2314 }
2315
2316 // ---------------------------------------------------------------------------
2317 // ObjrefException methods
2318 // ---------------------------------------------------------------------------
2319
2320 ObjrefException::ObjrefException()
2321 {
2322     LIMITED_METHOD_CONTRACT;
2323 }
2324
2325 ObjrefException::ObjrefException(OBJECTREF throwable)
2326 {
2327     CONTRACTL
2328     {
2329         THROWS;
2330         GC_NOTRIGGER;
2331         MODE_ANY;
2332     }
2333     CONTRACTL_END;
2334
2335     SetThrowableHandle(GetAppDomain()->CreateHandle(throwable));
2336 }
2337
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()
2346 {
2347     CONTRACTL
2348     {
2349         THROWS;
2350         GC_TRIGGERS;
2351         MODE_ANY;
2352     }
2353     CONTRACTL_END;
2354     GCX_COOP();
2355     return new ObjrefException(GetThrowable());
2356 }
2357
2358 // ---------------------------------------------------------------------------
2359 // CLRLastThrownException methods
2360 // ---------------------------------------------------------------------------
2361
2362 CLRLastThrownObjectException::CLRLastThrownObjectException()
2363 {
2364     LIMITED_METHOD_CONTRACT;
2365 }
2366
2367 Exception *CLRLastThrownObjectException::CloneHelper()
2368  {
2369     WRAPPER_NO_CONTRACT;
2370     GCX_COOP();
2371     return new ObjrefException(GetThrowable());
2372 }
2373   
2374 // ---------------------------------------------------------------------------
2375 // See ObjrefException::DomainBoundCloneHelper comments.
2376 // ---------------------------------------------------------------------------
2377 Exception *CLRLastThrownObjectException::DomainBoundCloneHelper()
2378 {
2379     CONTRACTL
2380     {
2381         THROWS;
2382         GC_TRIGGERS;
2383         MODE_ANY;
2384     }
2385     CONTRACTL_END;
2386     GCX_COOP();
2387     return new ObjrefException(GetThrowable());
2388 }
2389
2390 OBJECTREF CLRLastThrownObjectException::CreateThrowable()
2391 {
2392     CONTRACTL
2393     {
2394         NOTHROW;
2395         GC_NOTRIGGER;
2396         MODE_COOPERATIVE;
2397     }
2398     CONTRACTL_END;
2399
2400     DEBUG_STMT(Validate());
2401
2402     return GetThread()->LastThrownObject();
2403 } // OBJECTREF CLRLastThrownObjectException::CreateThrowable()
2404
2405 #if defined(_DEBUG)
2406 CLRLastThrownObjectException* CLRLastThrownObjectException::Validate()
2407 {
2408     CONTRACTL {
2409         NOTHROW;
2410         GC_NOTRIGGER;
2411         DEBUG_ONLY;
2412     }
2413     CONTRACTL_END;
2414     
2415     // Have to be in coop for GCPROTECT_BEGIN.
2416     GCX_COOP();
2417
2418     OBJECTREF throwable = NULL;
2419
2420     GCPROTECT_BEGIN(throwable);
2421
2422     Thread * pThread = GetThread();
2423     throwable = pThread->LastThrownObject();
2424
2425     DWORD dwCurrentExceptionCode = GetCurrentExceptionCode();
2426
2427     if (dwCurrentExceptionCode == BOOTUP_EXCEPTION_COMPLUS)
2428     {
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.
2431         //
2432         // If this exception is caught in EX_CATCH, there may not be any LTO setup since:
2433         //
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. 
2437         //
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.
2441         //
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:
2444         //
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. 
2448         
2449         // Clearly, BOOTUP_EXCEPTION_COMPLUS can also be caught in EX_CATCH. However:
2450         //
2451         // (A) above is not applicable since the exception is raised using RaiseException.
2452         //
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.
2456         //
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.
2460         //
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).
2463         //
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.
2465     }
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.)
2470
2471         static int iSuppress = -1;
2472         if (iSuppress == -1) 
2473             iSuppress = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuppressLostExceptionTypeAssert);
2474         if (!iSuppress)
2475         {   
2476             // Raising an assert message can  cause a mode violation.
2477             CONTRACT_VIOLATION(ModeViolation);
2478
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'");
2485         }
2486     }
2487
2488     GCPROTECT_END();
2489
2490     return this;
2491 } // CLRLastThrownObjectException* CLRLastThrownObjectException::Validate()
2492 #endif // _DEBUG
2493
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)
2499 {
2500     CONTRACTL
2501     {
2502         GC_TRIGGERS;
2503         THROWS;
2504         MODE_ANY;
2505     }
2506     CONTRACTL_END;
2507
2508     // If the Thread has been set up, then the LastThrownObject may make sense...
2509     if (GetThread())
2510     {
2511         // give back an object that knows about Threads and their exceptions.
2512         *ppException = new CLRLastThrownObjectException();
2513     }
2514     else
2515     {   
2516         // but if no Thread, don't pretend to know about LastThrownObject.
2517         *ppException = NULL;
2518     }
2519
2520 } // void GetLastThrownObjectExceptionFromThread_Internal()
2521
2522 #endif // CROSSGEN_COMPILE
2523
2524 //@TODO: Make available generally?
2525 // Wrapper class to encapsulate both array pointer and element count.
2526 template <typename T>
2527 class ArrayReference
2528 {
2529 public:
2530     typedef T value_type;
2531     typedef const typename std::remove_const<T>::type const_value_type;
2532
2533     typedef ArrayDPTR(value_type) array_type;
2534     typedef ArrayDPTR(const_value_type) const_array_type;
2535
2536     // Constructor taking array pointer and size.
2537     ArrayReference(array_type array, size_t size)
2538         : _array(dac_cast<array_type>(array))
2539         , _size(size)
2540     { LIMITED_METHOD_CONTRACT; }
2541
2542     // Constructor taking a statically sized array by reference.
2543     template <size_t N>
2544     ArrayReference(T (&array)[N])
2545         : _array(dac_cast<array_type>(&array[0]))
2546         , _size(N)
2547     { LIMITED_METHOD_CONTRACT; }
2548
2549     // Copy constructor.
2550     ArrayReference(ArrayReference const & other)
2551         : _array(other._array)
2552         , _size(other._size)
2553     { LIMITED_METHOD_CONTRACT; }
2554
2555     // Indexer
2556     template <typename IdxT>
2557     T & operator[](IdxT idx)
2558     { LIMITED_METHOD_CONTRACT; _ASSERTE(idx < _size); return _array[idx]; }
2559
2560     // Implicit conversion operators.
2561     operator array_type()
2562     { LIMITED_METHOD_CONTRACT; return _array; }
2563
2564     operator const_array_type() const
2565     { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array); }
2566
2567     // Returns the array element count.
2568     size_t size() const
2569     { LIMITED_METHOD_CONTRACT; return _size; }
2570
2571     // Iteration methods and types.
2572     typedef array_type iterator;
2573
2574     iterator begin()
2575     { LIMITED_METHOD_CONTRACT; return _array; }
2576
2577     iterator end()
2578     { LIMITED_METHOD_CONTRACT; return _array + _size; }
2579
2580     typedef const_array_type const_iterator;
2581
2582     const_iterator begin() const
2583     { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array); }
2584
2585     const_iterator end() const
2586     { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array) + _size; }
2587
2588 private:
2589     array_type   _array;
2590     size_t       _size;
2591 };
2592
2593 ArrayReference<const HRESULT> GetHRESULTsForExceptionKind(RuntimeExceptionKind kind)
2594 {
2595     LIMITED_METHOD_CONTRACT;
2596
2597     switch (kind)
2598     {
2599         #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...)    \
2600             case k##reKind:                                         \
2601                 return ArrayReference<const HRESULT>(s_##reKind##HRs);    \
2602                 break;
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__)
2605         #include "rexcep.h"
2606
2607         default:
2608             _ASSERTE(!"Unknown exception kind!");
2609             break;
2610             
2611     }
2612
2613     return ArrayReference<const HRESULT>(nullptr, 0);
2614 }
2615
2616 bool IsHRESULTForExceptionKind(HRESULT hr, RuntimeExceptionKind kind)
2617 {
2618     LIMITED_METHOD_CONTRACT;
2619
2620     ArrayReference<const HRESULT> rgHR = GetHRESULTsForExceptionKind(kind);
2621     for (ArrayReference<const HRESULT>::iterator i = rgHR.begin(); i != rgHR.end(); ++i)
2622     {
2623         if (*i == hr)
2624         {
2625             return true;
2626         }
2627     }
2628
2629     return false;
2630 }
2631
2632