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
33CLRException::~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 SO_TOLERANT;
49 }
50 CONTRACTL_END;
51
52#ifndef CROSSGEN_COMPILE
53 OBJECTHANDLE throwableHandle = GetThrowableHandle();
54 if (throwableHandle != NULL)
55 {
56 STRESS_LOG1(LF_EH, LL_INFO100, "CLRException::~CLRException destroying throwable: obj = %x\n", GetThrowableHandle());
57 // clear the handle first, so if we SO on destroying it, we don't have a dangling reference
58 SetThrowableHandle(NULL);
59 DestroyHandle(throwableHandle);
60 }
61#endif
62}
63
64OBJECTREF CLRException::GetThrowable()
65{
66 CONTRACTL
67 {
68 GC_TRIGGERS;
69 NOTHROW;
70 MODE_COOPERATIVE;
71 FORBID_FAULT;
72 }
73 CONTRACTL_END;
74
75#ifdef CROSSGEN_COMPILE
76 _ASSERTE(false);
77 return NULL;
78#else
79 OBJECTREF throwable = NULL;
80
81 if (NingenEnabled())
82 {
83 return NULL;
84 }
85
86 Thread *pThread = GetThread();
87
88 if (pThread->IsRudeAbortInitiated()) {
89 return GetPreallocatedRudeThreadAbortException();
90 }
91
92 if ((IsType(CLRLastThrownObjectException::GetType()) &&
93 pThread->LastThrownObject() == GetPreallocatedStackOverflowException()))
94 {
95 return GetPreallocatedStackOverflowException();
96 }
97
98 OBJECTHANDLE oh = GetThrowableHandle();
99 if (oh != NULL)
100 {
101 return ObjectFromHandle(oh);
102 }
103
104 Exception *pLastException = pThread->m_pCreatingThrowableForException;
105 if (pLastException != NULL)
106 {
107 if (IsSameInstanceType(pLastException))
108 {
109#if defined(_DEBUG)
110 static int BreakOnExceptionInGetThrowable = -1;
111 if (BreakOnExceptionInGetThrowable == -1)
112 {
113 BreakOnExceptionInGetThrowable = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnExceptionInGetThrowable);
114 }
115 if (BreakOnExceptionInGetThrowable)
116 {
117 _ASSERTE(!"BreakOnExceptionInGetThrowable");
118 }
119 LOG((LF_EH, LL_INFO100, "GetThrowable: Exception in GetThrowable, translating to a preallocated exception.\n"));
120#endif // _DEBUG
121 // Look at the type of GET_EXCEPTION() and see if it is OOM or SO.
122 if (IsPreallocatedOOMException())
123 {
124 throwable = GetPreallocatedOutOfMemoryException();
125 }
126 else if (GetInstanceType() == EEException::GetType() && GetHR() == COR_E_THREADABORTED)
127 {
128 // If creating a normal ThreadAbortException fails, due to OOM or StackOverflow,
129 // use a pre-created one.
130 // We do not won't to change a ThreadAbortException into OOM or StackOverflow, because
131 // it will cause recursive call when escalation policy is on:
132 // Creating ThreadAbortException fails, we throw OOM. Escalation leads to ThreadAbort.
133 // The cycle repeats.
134 throwable = GetPreallocatedThreadAbortException();
135 }
136 else
137 {
138 // I am not convinced if this case is actually a fatal error in the runtime.
139 // There have been two bugs in early 2006 (VSW 575647 and 575650) that came in here,
140 // both because of OOM and resulted in the ThreadAbort clause above being added since
141 // we were creating a ThreadAbort throwable that, due to OOM, got us on a path
142 // which came here. Both were valid execution paths and scenarios and not a fatal condition.
143 //
144 // I am tempted to return preallocated OOM from here but my concern is that it *may*
145 // result in fake OOM exceptions being thrown that could break valid scenarios.
146 //
147 // Hence, we return preallocated System.Exception instance. Lossy information is better
148 // than wrong or no information (or even FailFast).
149 _ASSERTE (!"Recursion in CLRException::GetThrowable");
150
151 // We didn't recognize it, so use the preallocated System.Exception instance.
152 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowable: Recursion! Translating to preallocated System.Exception.\n");
153 throwable = GetPreallocatedBaseException();
154 }
155 }
156 }
157
158 GCPROTECT_BEGIN(throwable);
159
160 if (throwable == NULL)
161 {
162 // We need to disable the backout stack validation at this point since GetThrowable can
163 // take arbitrarily large amounts of stack for different exception types; however we know
164 // for a fact that we will never go through this code path if the exception is a stack
165 // overflow exception since we already handled that case above with the pre-allocated SO exception.
166 DISABLE_BACKOUT_STACK_VALIDATION;
167
168 class RestoreLastException
169 {
170 Thread *m_pThread;
171 Exception *m_pLastException;
172 public:
173 RestoreLastException(Thread *pThread, Exception *pException)
174 {
175 m_pThread = pThread;
176 m_pLastException = m_pThread->m_pCreatingThrowableForException;
177 m_pThread->m_pCreatingThrowableForException = pException;
178 }
179 ~RestoreLastException()
180 {
181 m_pThread->m_pCreatingThrowableForException = m_pLastException;
182 }
183 };
184
185 RestoreLastException restore(pThread, this);
186
187 EX_TRY
188 {
189 FAULT_NOT_FATAL();
190 throwable = CreateThrowable();
191 }
192 EX_CATCH
193 {
194 // This code used to be this line:
195 // throwable = GET_THROWABLE();
196 // GET_THROWABLE() expands to CLRException::GetThrowable(GET_EXCEPTION()),
197 // (where GET_EXCEPTION() refers to the exception that was thrown from
198 // CreateThrowable() and is being caught in this EX_TRY/EX_CATCH.)
199 // If that exception is the same as the one for which this GetThrowable()
200 // was called, we're in a recursive situation.
201 // Since the CreateThrowable() call should return a type from mscorlib,
202 // there really shouldn't be much opportunity for error. We could be
203 // out of memory, we could overflow the stack, or the runtime could
204 // be in a weird state(the thread could be aborted as well).
205 // Because we've seen a number of recursive death bugs here, just look
206 // explicitly for OOM and SO, and otherwise use ExecutionEngineException.
207
208 // Check whether the exception from CreateThrowable() is the same as the current
209 // exception. If not, call GetThrowable(), otherwise, settle for a
210 // preallocated exception.
211 Exception *pException = GET_EXCEPTION();
212
213 if (GetHR() == COR_E_THREADABORTED)
214 {
215 // If creating a normal ThreadAbortException fails, due to OOM or StackOverflow,
216 // use a pre-created one.
217 // We do not won't to change a ThreadAbortException into OOM or StackOverflow, because
218 // it will cause recursive call when escalation policy is on:
219 // Creating ThreadAbortException fails, we throw OOM. Escalation leads to ThreadAbort.
220 // The cycle repeats.
221 throwable = GetPreallocatedThreadAbortException();
222 }
223 else
224 {
225 throwable = CLRException::GetThrowableFromException(pException);
226 }
227 }
228 EX_END_CATCH(SwallowAllExceptions)
229
230 }
231
232 {
233 DISABLE_BACKOUT_STACK_VALIDATION;
234 if (throwable == NULL)
235 {
236 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowable: We have failed to track exceptions accurately through the system.\n");
237
238 // There's no reason to believe that it is an OOM. A better choice is ExecutionEngineException.
239 // We have failed to track exceptions accurately through the system. However, it's arguably
240 // better to give the wrong exception object than it is to rip the process. So let's leave
241 // it as an Assert for now and convert it to ExecutionEngineException in the next release.
242
243 // SQL Stress is hitting the assert. We want to remove it, so that we can see if there are further errors
244 // masked by the assert.
245 // _ASSERTE(FALSE);
246
247 throwable = GetPreallocatedOutOfMemoryException();
248 }
249
250 EX_TRY
251 {
252 SetThrowableHandle(GetAppDomain()->CreateHandle(throwable));
253 if (m_innerException != NULL && !CLRException::IsPreallocatedExceptionObject(throwable))
254 {
255 // Only set inner exception if the exception is not preallocated.
256 FAULT_NOT_FATAL();
257
258 // If inner exception is not empty, then set the managed exception's
259 // _innerException field properly
260 OBJECTREF throwableValue = CLRException::GetThrowableFromException(m_innerException);
261 ((EXCEPTIONREF)throwable)->SetInnerException(throwableValue);
262 }
263
264 }
265 EX_CATCH
266 {
267 // No matter... we just don't get to cache the throwable.
268 }
269 EX_END_CATCH(SwallowAllExceptions)
270 }
271
272 GCPROTECT_END();
273
274 return throwable;
275#endif
276}
277
278HRESULT CLRException::GetHR()
279{
280 CONTRACTL
281 {
282 DISABLED(NOTHROW);
283 GC_TRIGGERS;
284 MODE_ANY;
285 SO_TOLERANT;
286 }
287 CONTRACTL_END;
288
289 HRESULT hr = E_FAIL;
290
291 BEGIN_SO_INTOLERANT_CODE(GetThread());
292
293// Is it legal to switch to GCX_COOP in a SO_TOLERANT region?
294 GCX_COOP();
295 hr = GetExceptionHResult(GetThrowable());
296
297 END_SO_INTOLERANT_CODE;
298
299 return hr;
300}
301
302#ifdef FEATURE_COMINTEROP
303HRESULT CLRException::SetErrorInfo()
304{
305 CONTRACTL
306 {
307 GC_TRIGGERS;
308 NOTHROW;
309 MODE_ANY;
310 SO_TOLERANT;
311 }
312 CONTRACTL_END;
313
314 HRESULT hr = S_OK;
315
316 IErrorInfo *pErrorInfo = NULL;
317
318 // Try to get IErrorInfo
319 EX_TRY
320 {
321 pErrorInfo = GetErrorInfo();
322 }
323 EX_CATCH
324 {
325 // Since there was an exception getting IErrorInfo get the exception's HR so
326 // that we return it back to the caller as the new exception.
327 hr = GET_EXCEPTION()->GetHR();
328 pErrorInfo = NULL;
329 LOG((LF_EH, LL_INFO100, "CLRException::SetErrorInfo: caught exception (hr = %08X) while trying to get IErrorInfo\n", hr));
330 }
331 EX_END_CATCH(SwallowAllExceptions)
332
333 if (!pErrorInfo)
334 {
335 // Return the HR to the caller if we dont get IErrorInfo - if the HR is E_NOINTERFACE, then
336 // there was no IErrorInfo available. If its anything else, it implies we failed to get the
337 // interface and have the HR corresponding to the exception we took while trying to get IErrorInfo.
338 return hr;
339 }
340 else
341 {
342 GCX_PREEMP();
343
344 EX_TRY
345 {
346 ::SetErrorInfo(0, pErrorInfo);
347 pErrorInfo->Release();
348
349 // Success in setting the ErrorInfo on the thread
350 hr = S_OK;
351 }
352 EX_CATCH
353 {
354 hr = GET_EXCEPTION()->GetHR();
355 // Log the failure
356 LOG((LF_EH, LL_INFO100, "CLRException::SetErrorInfo: caught exception (hr = %08X) while trying to set IErrorInfo\n", hr));
357 }
358 EX_END_CATCH(SwallowAllExceptions)
359 }
360
361 return hr;
362}
363
364IErrorInfo *CLRException::GetErrorInfo()
365{
366 CONTRACTL
367 {
368 GC_TRIGGERS;
369 THROWS;
370 MODE_ANY;
371 SO_TOLERANT;
372 }
373 CONTRACTL_END;
374
375 IErrorInfo *pErrorInfo = NULL;
376
377#ifndef CROSSGEN_COMPILE
378 // Attempt to get IErrorInfo only if COM is initialized.
379 // Not all codepaths expect to have it initialized (e.g. hosting APIs).
380 if (g_fComStarted)
381 {
382 // We probe here for SO since GetThrowable and GetComIPFromObjectRef are SO intolerant
383 BEGIN_SO_INTOLERANT_CODE(GetThread());
384
385 // Get errorinfo only when our SO probe succeeds
386 {
387 // Switch to coop mode since GetComIPFromObjectRef requires that
388 // and we could be here in any mode...
389 GCX_COOP();
390
391 OBJECTREF e = NULL;
392 GCPROTECT_BEGIN(e);
393
394 e = GetThrowable();
395
396 if (e != NULL)
397 {
398 pErrorInfo = (IErrorInfo *)GetComIPFromObjectRef(&e, IID_IErrorInfo);
399 }
400
401 GCPROTECT_END();
402 }
403
404 END_SO_INTOLERANT_CODE;
405 }
406 else
407 {
408 // Write to the log incase COM isnt initialized.
409 LOG((LF_EH, LL_INFO100, "CLRException::GetErrorInfo: exiting since COM is not initialized.\n"));
410 }
411#endif //CROSSGEN_COMPILE
412
413 // return the IErrorInfo we got...
414 return pErrorInfo;
415}
416#else // FEATURE_COMINTEROP
417IErrorInfo *CLRException::GetErrorInfo()
418{
419 LIMITED_METHOD_CONTRACT;
420 return NULL;
421}
422HRESULT CLRException::SetErrorInfo()
423{
424 LIMITED_METHOD_CONTRACT;
425
426 return S_OK;
427 }
428#endif // FEATURE_COMINTEROP
429
430void CLRException::GetMessage(SString &result)
431{
432 CONTRACTL
433 {
434 GC_TRIGGERS;
435 THROWS;
436 MODE_ANY;
437 }
438 CONTRACTL_END;
439
440#ifndef CROSSGEN_COMPILE
441 GCX_COOP();
442
443 OBJECTREF e = GetThrowable();
444 if (e != NULL)
445 {
446 _ASSERTE(IsException(e->GetMethodTable()));
447
448 GCPROTECT_BEGIN (e);
449
450 STRINGREF message = ((EXCEPTIONREF)e)->GetMessage();
451
452 if (!message)
453 result.Clear();
454 else
455 message->GetSString(result);
456
457 GCPROTECT_END ();
458 }
459#endif
460}
461
462#ifndef CROSSGEN_COMPILE
463OBJECTREF CLRException::GetPreallocatedBaseException()
464{
465 WRAPPER_NO_CONTRACT;
466 _ASSERTE(g_pPreallocatedBaseException != NULL);
467 return ObjectFromHandle(g_pPreallocatedBaseException);
468}
469
470OBJECTREF CLRException::GetPreallocatedOutOfMemoryException()
471{
472 WRAPPER_NO_CONTRACT;
473 _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
474 return ObjectFromHandle(g_pPreallocatedOutOfMemoryException);
475}
476
477OBJECTREF CLRException::GetPreallocatedStackOverflowException()
478{
479 WRAPPER_NO_CONTRACT;
480 _ASSERTE(g_pPreallocatedStackOverflowException != NULL);
481 return ObjectFromHandle(g_pPreallocatedStackOverflowException);
482}
483
484OBJECTREF CLRException::GetPreallocatedExecutionEngineException()
485{
486 WRAPPER_NO_CONTRACT;
487 _ASSERTE(g_pPreallocatedExecutionEngineException != NULL);
488 return ObjectFromHandle(g_pPreallocatedExecutionEngineException);
489}
490
491OBJECTREF CLRException::GetPreallocatedRudeThreadAbortException()
492{
493 WRAPPER_NO_CONTRACT;
494 // When we are hosted, we pre-create this exception.
495 // This function should be called only if the exception has been created.
496 _ASSERTE(g_pPreallocatedRudeThreadAbortException);
497 return ObjectFromHandle(g_pPreallocatedRudeThreadAbortException);
498}
499
500OBJECTREF CLRException::GetPreallocatedThreadAbortException()
501{
502 WRAPPER_NO_CONTRACT;
503 _ASSERTE(g_pPreallocatedThreadAbortException);
504 return ObjectFromHandle(g_pPreallocatedThreadAbortException);
505}
506
507OBJECTHANDLE CLRException::GetPreallocatedOutOfMemoryExceptionHandle()
508{
509 LIMITED_METHOD_CONTRACT;
510 _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
511 return g_pPreallocatedOutOfMemoryException;
512}
513
514OBJECTHANDLE CLRException::GetPreallocatedThreadAbortExceptionHandle()
515{
516 LIMITED_METHOD_CONTRACT;
517 _ASSERTE(g_pPreallocatedThreadAbortException != NULL);
518 return g_pPreallocatedThreadAbortException;
519}
520
521OBJECTHANDLE CLRException::GetPreallocatedRudeThreadAbortExceptionHandle()
522{
523 LIMITED_METHOD_CONTRACT;
524 _ASSERTE(g_pPreallocatedRudeThreadAbortException != NULL);
525 return g_pPreallocatedRudeThreadAbortException;
526}
527
528OBJECTHANDLE CLRException::GetPreallocatedStackOverflowExceptionHandle()
529{
530 LIMITED_METHOD_CONTRACT;
531 _ASSERTE(g_pPreallocatedStackOverflowException != NULL);
532 return g_pPreallocatedStackOverflowException;
533}
534
535OBJECTHANDLE CLRException::GetPreallocatedExecutionEngineExceptionHandle()
536{
537 LIMITED_METHOD_CONTRACT;
538 _ASSERTE(g_pPreallocatedExecutionEngineException != NULL);
539 return g_pPreallocatedExecutionEngineException;
540}
541
542//
543// Returns TRUE if the given object ref is one of the preallocated exception objects.
544//
545BOOL CLRException::IsPreallocatedExceptionObject(OBJECTREF o)
546{
547 CONTRACTL
548 {
549 NOTHROW;
550 GC_NOTRIGGER;
551 MODE_COOPERATIVE;
552 FORBID_FAULT;
553 SO_TOLERANT;
554 }
555 CONTRACTL_END;
556
557 if ((o == ObjectFromHandle(g_pPreallocatedBaseException)) ||
558 (o == ObjectFromHandle(g_pPreallocatedOutOfMemoryException)) ||
559 (o == ObjectFromHandle(g_pPreallocatedStackOverflowException)) ||
560 (o == ObjectFromHandle(g_pPreallocatedExecutionEngineException)))
561 {
562 return TRUE;
563 }
564
565 // The preallocated rude thread abort exception is not always preallocated.
566 if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
567 (o == ObjectFromHandle(g_pPreallocatedRudeThreadAbortException)))
568 {
569 return TRUE;
570 }
571
572 // The preallocated rude thread abort exception is not always preallocated.
573 if ((g_pPreallocatedThreadAbortException != NULL) &&
574 (o == ObjectFromHandle(g_pPreallocatedThreadAbortException)))
575 {
576 return TRUE;
577 }
578
579 return FALSE;
580}
581
582//
583// Returns TRUE if the given object ref is one of the preallocated exception handles
584//
585BOOL CLRException::IsPreallocatedExceptionHandle(OBJECTHANDLE h)
586{
587 CONTRACTL
588 {
589 NOTHROW;
590 GC_NOTRIGGER;
591 MODE_ANY;
592 FORBID_FAULT;
593 SO_TOLERANT;
594 }
595 CONTRACTL_END;
596
597 if ((h == g_pPreallocatedBaseException) ||
598 (h == g_pPreallocatedOutOfMemoryException) ||
599 (h == g_pPreallocatedStackOverflowException) ||
600 (h == g_pPreallocatedExecutionEngineException) ||
601 (h == g_pPreallocatedThreadAbortException))
602 {
603 return TRUE;
604 }
605
606 // The preallocated rude thread abort exception is not always preallocated.
607 if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
608 (h == g_pPreallocatedRudeThreadAbortException))
609 {
610 return TRUE;
611 }
612
613 return FALSE;
614}
615
616//
617// Returns a preallocated handle to match a preallocated exception object, or NULL if the object isn't one of the
618// preallocated exception objects.
619//
620OBJECTHANDLE CLRException::GetPreallocatedHandleForObject(OBJECTREF o)
621{
622 CONTRACTL
623 {
624 NOTHROW;
625 GC_NOTRIGGER;
626 MODE_COOPERATIVE;
627 FORBID_FAULT;
628 SO_TOLERANT;
629 }
630 CONTRACTL_END;
631
632 if (o == ObjectFromHandle(g_pPreallocatedBaseException))
633 {
634 return g_pPreallocatedBaseException;
635 }
636 else if (o == ObjectFromHandle(g_pPreallocatedOutOfMemoryException))
637 {
638 return g_pPreallocatedOutOfMemoryException;
639 }
640 else if (o == ObjectFromHandle(g_pPreallocatedStackOverflowException))
641 {
642 return g_pPreallocatedStackOverflowException;
643 }
644 else if (o == ObjectFromHandle(g_pPreallocatedExecutionEngineException))
645 {
646 return g_pPreallocatedExecutionEngineException;
647 }
648 else if (o == ObjectFromHandle(g_pPreallocatedThreadAbortException))
649 {
650 return g_pPreallocatedThreadAbortException;
651 }
652
653 // The preallocated rude thread abort exception is not always preallocated.
654 if ((g_pPreallocatedRudeThreadAbortException != NULL) &&
655 (o == ObjectFromHandle(g_pPreallocatedRudeThreadAbortException)))
656 {
657 return g_pPreallocatedRudeThreadAbortException;
658 }
659
660 return NULL;
661}
662
663// Prefer a new OOM exception if we can make one. If we cannot, then give back the pre-allocated one.
664OBJECTREF CLRException::GetBestOutOfMemoryException()
665{
666 CONTRACTL
667 {
668 NOTHROW;
669 MODE_COOPERATIVE;
670 SO_TOLERANT;
671 }
672 CONTRACTL_END;
673
674 OBJECTREF retVal = NULL;
675
676 EX_TRY
677 {
678 FAULT_NOT_FATAL();
679
680 BEGIN_SO_INTOLERANT_CODE(GetThread());
681
682 EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
683 pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
684 pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
685
686 retVal = pOutOfMemory;
687
688 END_SO_INTOLERANT_CODE;
689 }
690 EX_CATCH
691 {
692 retVal = GetPreallocatedOutOfMemoryException();
693 }
694 EX_END_CATCH(SwallowAllExceptions)
695
696 _ASSERTE(retVal != NULL);
697
698 return retVal;
699}
700
701
702// Works on non-CLRExceptions as well
703// static function
704OBJECTREF CLRException::GetThrowableFromException(Exception *pException)
705{
706 CONTRACTL
707 {
708 GC_TRIGGERS;
709 NOTHROW;
710 MODE_COOPERATIVE;
711 SO_INTOLERANT;
712 }
713 CONTRACTL_END;
714
715 Thread* pThread = GetThread();
716
717 // Can't have a throwable without a Thread.
718 _ASSERTE(pThread != NULL);
719
720 if (NULL == pException)
721 {
722 return pThread->LastThrownObject();
723 }
724
725 if (pException->IsType(CLRException::GetType()))
726 return ((CLRException*)pException)->GetThrowable();
727
728 if (pException->IsType(EEException::GetType()))
729 return ((EEException*)pException)->GetThrowable();
730
731 // Note: we are creating a throwable on the fly in this case - so
732 // multiple calls will return different objects. If we really need identity,
733 // we could store a throwable handle at the catch site, or store it
734 // on the thread object.
735
736 if (pException->IsType(SEHException::GetType()))
737 {
738 SEHException *pSEHException = (SEHException*)pException;
739
740 switch (pSEHException->m_exception.ExceptionCode)
741 {
742 case EXCEPTION_COMPLUS:
743 // Note: even though the switch compared the exception code,
744 // we have to call the official IsComPlusException() routine
745 // for side-by-side correctness. If that check fails, treat
746 // as an unrelated unmanaged exception.
747 if (IsComPlusException(&(pSEHException->m_exception)))
748 {
749 return pThread->LastThrownObject();
750 }
751 else
752 {
753 break;
754 }
755
756 case STATUS_NO_MEMORY:
757 return GetBestOutOfMemoryException();
758
759 case STATUS_STACK_OVERFLOW:
760 return GetPreallocatedStackOverflowException();
761 }
762
763 DWORD exceptionCode =
764 MapWin32FaultToCOMPlusException(&pSEHException->m_exception);
765
766 EEException e((RuntimeExceptionKind)exceptionCode);
767
768 OBJECTREF throwable = e.GetThrowable();
769 GCPROTECT_BEGIN (throwable);
770 EX_TRY
771 {
772 SCAN_IGNORE_FAULT;
773 if (throwable != NULL && !CLRException::IsPreallocatedExceptionObject(throwable))
774 {
775 _ASSERTE(IsException(throwable->GetMethodTable()));
776
777 // set the exception code
778 ((EXCEPTIONREF)throwable)->SetXCode(pSEHException->m_exception.ExceptionCode);
779 }
780 }
781 EX_CATCH
782 {
783 }
784 EX_END_CATCH(SwallowAllExceptions)
785 GCPROTECT_END ();
786
787 return throwable;
788 }
789 else
790 {
791 // We can enter here for HRException, COMException, DelegatingException
792 // just to name a few.
793 OBJECTREF oRetVal = NULL;
794 GCPROTECT_BEGIN(oRetVal);
795 {
796 EX_TRY
797 {
798 HRESULT hr = pException->GetHR();
799
800 if (hr == E_OUTOFMEMORY || hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY))
801 {
802 oRetVal = GetBestOutOfMemoryException();
803 }
804 else if (hr == COR_E_STACKOVERFLOW)
805 {
806 oRetVal = GetPreallocatedStackOverflowException();
807 }
808 else
809 {
810 SafeComHolder<IErrorInfo> pErrInfo(pException->GetErrorInfo());
811
812 if (pErrInfo != NULL)
813 {
814 GetExceptionForHR(hr, pErrInfo, &oRetVal);
815 }
816 else
817 {
818 SString message;
819 pException->GetMessage(message);
820
821 EEMessageException e(hr, IDS_EE_GENERIC, message);
822
823 oRetVal = e.CreateThrowable();
824 }
825 }
826 }
827 EX_CATCH
828 {
829 // We have caught an exception trying to get a Throwable for the pException we
830 // were given. It is tempting to want to get the Throwable for the new
831 // exception, but that is dangerous, due to infinitely cascading
832 // exceptions, leading to a stack overflow.
833
834 // If we can see that the exception was OOM, return the preallocated OOM,
835 // if we can see that it is SO, return the preallocated SO,
836 // if we can see that it is some other managed exception, return that
837 // exception, otherwise return the preallocated System.Exception.
838 Exception *pNewException = GET_EXCEPTION();
839
840 if (pNewException->IsPreallocatedOOMException())
841 { // It definitely was an OOM
842 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: OOM creating throwable; getting pre-alloc'd OOM.\n");
843 if (oRetVal == NULL)
844 oRetVal = GetPreallocatedOutOfMemoryException();
845 }
846 else
847 if (pNewException->IsType(CLRLastThrownObjectException::GetType()) &&
848 (pThread->LastThrownObject() != NULL))
849 {
850 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: LTO Exception creating throwable; getting LastThrownObject.\n");
851 if (oRetVal == NULL)
852 oRetVal = pThread->LastThrownObject();
853 }
854 else
855 {
856 // We *could* come here if one of the calls in the EX_TRY above throws an exception (e.g. MissingMethodException if we attempt
857 // to invoke CreateThrowable for a type that does not have a default constructor) that is neither preallocated OOM nor a
858 // CLRLastThrownObject type.
859 //
860 // 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
861 // but we dont know what to return as well. A reasonable answer is to return something less appropriate than ripping down process
862 // or returning an incorrect exception (e.g. OOM) that could break execution paths.
863 //
864 // Hence, we return preallocated System.Exception instance.
865 if (oRetVal == NULL)
866 {
867 oRetVal = GetPreallocatedBaseException();
868 STRESS_LOG0(LF_EH, LL_INFO100, "CLRException::GetThrowableFromException: Unknown Exception creating throwable; getting preallocated System.Exception.\n");
869 }
870 }
871
872 }
873 EX_END_CATCH(SwallowAllExceptions)
874 }
875 GCPROTECT_END();
876
877 return oRetVal;
878 }
879} // OBJECTREF CLRException::GetThrowableFromException()
880
881OBJECTREF CLRException::GetThrowableFromExceptionRecord(EXCEPTION_RECORD *pExceptionRecord)
882{
883 CONTRACTL
884 {
885 GC_NOTRIGGER;
886 NOTHROW;
887 MODE_ANY;
888 SO_TOLERANT;
889 }
890 CONTRACTL_END;
891
892 if (IsComPlusException(pExceptionRecord))
893 {
894 return GetThread()->LastThrownObject();
895 }
896
897 return NULL;
898}
899
900void CLRException::HandlerState::CleanupTry()
901{
902 STATIC_CONTRACT_NOTHROW;
903 STATIC_CONTRACT_GC_NOTRIGGER;
904 STATIC_CONTRACT_MODE_ANY;
905 STATIC_CONTRACT_SO_TOLERANT;
906
907 if (m_pThread != NULL)
908 {
909 BEGIN_GETTHREAD_ALLOWED;
910 // If there is no frame to unwind, UnwindFrameChain call is just an expensive NOP
911 // due to setting up and tear down of EH records. So we avoid it if we can.
912 if (m_pThread->GetFrame() < m_pFrame)
913 UnwindFrameChain(m_pThread, m_pFrame);
914
915 if (m_fPreemptiveGCDisabled != m_pThread->PreemptiveGCDisabled())
916 {
917 if (m_fPreemptiveGCDisabled)
918 m_pThread->DisablePreemptiveGC();
919 else
920 m_pThread->EnablePreemptiveGC();
921 }
922 END_GETTHREAD_ALLOWED;
923 }
924
925 // Make sure to call the base class's CleanupTry so it can do whatever it wants to do.
926 Exception::HandlerState::CleanupTry();
927}
928
929void CLRException::HandlerState::SetupCatch(INDEBUG_COMMA(__in_z const char * szFile) int lineNum)
930{
931 STATIC_CONTRACT_NOTHROW;
932 STATIC_CONTRACT_GC_NOTRIGGER;
933 STATIC_CONTRACT_MODE_ANY;
934 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
935 STATIC_CONTRACT_SO_TOLERANT;
936
937 bool fVMInitialized = g_fEEStarted?true:false;
938 Exception::HandlerState::SetupCatch(INDEBUG_COMMA(szFile) lineNum, fVMInitialized);
939
940 Thread *pThread = NULL;
941 DWORD exceptionCode = 0;
942
943 if (fVMInitialized)
944 {
945 pThread = GetThread();
946 exceptionCode = GetCurrentExceptionCode();
947 }
948
949 if (!DidCatchCxx())
950 {
951 if (IsSOExceptionCode(exceptionCode))
952 {
953 // Handle SO exception
954 //
955 // We should ensure that a valid Thread object exists before trying to set SO as the LTO.
956 if (pThread != NULL)
957 {
958 // We have a nasty issue with our EX_TRY/EX_CATCH. If EX_CATCH catches SEH exception,
959 // GET_THROWABLE uses CLRLastThrownObjectException instead, because we don't know
960 // what exception to use. But for SO, we can use preallocated SO exception.
961 GCX_COOP();
962 pThread->SetSOForLastThrownObject();
963 }
964
965 if (exceptionCode == STATUS_STACK_OVERFLOW)
966 {
967 // We have called HandleStackOverflow for soft SO through our vectored exception handler.
968 EEPolicy::HandleStackOverflow(SOD_UnmanagedFrameHandler, FRAME_TOP);
969 }
970 }
971 }
972
973#ifdef WIN64EXCEPTIONS
974 if (!DidCatchCxx())
975 {
976 // this must be done after the second pass has run, it does not
977 // reference anything on the stack, so it is safe to run in an
978 // SEH __except clause as well as a C++ catch clause.
979 ExceptionTracker::PopTrackers(this);
980 }
981#endif // WIN64EXCEPTIONS
982}
983
984#ifdef LOGGING
985void CLRException::HandlerState::SucceedCatch()
986{
987 STATIC_CONTRACT_NOTHROW;
988 STATIC_CONTRACT_GC_NOTRIGGER;
989 STATIC_CONTRACT_MODE_ANY;
990 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
991 STATIC_CONTRACT_SO_TOLERANT;
992
993 LOG((LF_EH, LL_INFO100, "EX_CATCH catch succeeded (CLRException::HandlerState)\n"));
994
995 //
996 // At this point, we don't believe we need to do any unwinding of the ExInfo chain after an EX_CATCH. The chain
997 // is unwound by CPFH_UnwindFrames1() when it detects that the exception is being caught by an unmanaged
998 // catcher. EX_CATCH looks just like an unmanaged catcher now, so the unwind is already done by the time we get
999 // into the catch. That's different than before the big switch to the new exeption system, and it effects
1000 // rethrows. Fixing rethrows is a work item for a little later. For now, we're simplying removing the unwind
1001 // from here to avoid the extra unwind, which is harmless in many cases, but is very harmful when a managed
1002 // filter throws an exception.
1003 //
1004 //
1005
1006 Exception::HandlerState::SucceedCatch();
1007}
1008#endif
1009
1010#endif // CROSSGEN_COMPILE
1011
1012// ---------------------------------------------------------------------------
1013// EEException methods
1014// ---------------------------------------------------------------------------
1015
1016//------------------------------------------------------------------------
1017// Array that is used to retrieve the right exception for a given HRESULT.
1018//------------------------------------------------------------------------
1019
1020#ifdef FEATURE_COMINTEROP
1021
1022struct WinRtHR_to_ExceptionKind_Map
1023{
1024 RuntimeExceptionKind reKind;
1025 int cHRs;
1026 const HRESULT *aHRs;
1027};
1028
1029enum WinRtOnly_ExceptionKind {
1030#define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) kWinRtEx##reKind,
1031#define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...)
1032#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...)
1033#include "rexcep.h"
1034kWinRtExLastException
1035};
1036
1037#define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) static const HRESULT s_##reKind##WinRtOnlyHRs[] = { __VA_ARGS__ };
1038#define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...)
1039#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...)
1040#include "rexcep.h"
1041
1042static const
1043WinRtHR_to_ExceptionKind_Map gWinRtHR_to_ExceptionKind_Maps[] = {
1044#define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) { k##reKind, sizeof(s_##reKind##WinRtOnlyHRs) / sizeof(HRESULT), s_##reKind##WinRtOnlyHRs },
1045#define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...)
1046#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...)
1047#include "rexcep.h"
1048};
1049
1050#endif // FEATURE_COMINTEROP
1051
1052struct ExceptionHRInfo
1053{
1054 int cHRs;
1055 const HRESULT *aHRs;
1056};
1057
1058#define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) static const HRESULT s_##reKind##HRs[] = { __VA_ARGS__ };
1059#define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
1060#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
1061#include "rexcep.h"
1062
1063static const
1064ExceptionHRInfo gExceptionHRInfos[] = {
1065#define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) {sizeof(s_##reKind##HRs) / sizeof(HRESULT), s_##reKind##HRs},
1066#define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
1067#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
1068#include "rexcep.h"
1069};
1070
1071
1072static const
1073bool gShouldDisplayHR[] =
1074{
1075#define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) bHRformessage,
1076#define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
1077#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
1078#include "rexcep.h"
1079};
1080
1081
1082/*static*/
1083HRESULT EEException::GetHRFromKind(RuntimeExceptionKind reKind)
1084{
1085 LIMITED_METHOD_CONTRACT;
1086 return gExceptionHRInfos[reKind].aHRs[0];
1087}
1088
1089HRESULT EEException::GetHR()
1090{
1091 LIMITED_METHOD_CONTRACT;
1092
1093 return EEException::GetHRFromKind(m_kind);
1094}
1095
1096IErrorInfo *EEException::GetErrorInfo()
1097{
1098 LIMITED_METHOD_CONTRACT;
1099
1100 return NULL;
1101}
1102
1103BOOL EEException::GetThrowableMessage(SString &result)
1104{
1105 CONTRACTL
1106 {
1107 GC_TRIGGERS;
1108 THROWS;
1109 MODE_ANY;
1110 }
1111 CONTRACTL_END;
1112
1113 // Return a meaningful HR message, if there is one.
1114
1115 HRESULT hr = GetHR();
1116
1117 // If the hr is more interesting than the kind, use that
1118 // for a message.
1119
1120 if (hr != S_OK
1121 && hr != E_FAIL
1122 && (gShouldDisplayHR[m_kind]
1123 || gExceptionHRInfos[m_kind].aHRs[0] != hr))
1124 {
1125 // If it has only one HR, the original message should be good enough
1126 _ASSERTE(gExceptionHRInfos[m_kind].cHRs > 1 ||
1127 gExceptionHRInfos[m_kind].aHRs[0] != hr);
1128
1129 GenerateTopLevelHRExceptionMessage(hr, result);
1130 return TRUE;
1131 }
1132
1133 // No interesting hr - just keep the class default message.
1134
1135 return FALSE;
1136}
1137
1138void EEException::GetMessage(SString &result)
1139{
1140 CONTRACTL
1141 {
1142 GC_TRIGGERS;
1143 THROWS;
1144 MODE_ANY;
1145 }
1146 CONTRACTL_END;
1147
1148 // First look for a specialized message
1149 if (GetThrowableMessage(result))
1150 return;
1151
1152 // Otherwise, report the class's generic message
1153 LPCUTF8 pszExceptionName = NULL;
1154 if (m_kind <= kLastExceptionInMscorlib)
1155 {
1156 pszExceptionName = MscorlibBinder::GetExceptionName(m_kind);
1157 result.SetUTF8(pszExceptionName);
1158 }
1159#ifndef CROSSGEN_COMPILE
1160 else
1161 {
1162 FrameworkExceptionLoader::GetExceptionName(m_kind, result);
1163 }
1164#endif // CROSSGEN_COMPILE
1165}
1166
1167OBJECTREF EEException::CreateThrowable()
1168{
1169#ifdef CROSSGEN_COMPILE
1170 _ASSERTE(false);
1171 return NULL;
1172#else
1173 CONTRACTL
1174 {
1175 GC_TRIGGERS;
1176 THROWS;
1177 MODE_COOPERATIVE;
1178 }
1179 CONTRACTL_END;
1180
1181 _ASSERTE(g_pPreallocatedOutOfMemoryException != NULL);
1182 static int allocCount = 0;
1183
1184 MethodTable *pMT = NULL;
1185 if (m_kind <= kLastExceptionInMscorlib)
1186 pMT = MscorlibBinder::GetException(m_kind);
1187 else
1188 {
1189 pMT = FrameworkExceptionLoader::GetException(m_kind);
1190 }
1191
1192 ThreadPreventAsyncHolder preventAsyncHolder(m_kind == kThreadAbortException);
1193
1194 OBJECTREF throwable = AllocateObject(pMT);
1195 allocCount++;
1196 GCPROTECT_BEGIN(throwable);
1197
1198 {
1199 ThreadPreventAsyncHolder preventAbort(m_kind == kThreadAbortException ||
1200 m_kind == kThreadInterruptedException);
1201 CallDefaultConstructor(throwable);
1202 }
1203
1204 HRESULT hr = GetHR();
1205 ((EXCEPTIONREF)throwable)->SetHResult(hr);
1206
1207 SString message;
1208 if (GetThrowableMessage(message))
1209 {
1210 // Set the message field. It is not safe doing this through the constructor
1211 // since the string constructor for some exceptions add a prefix to the message
1212 // which we don't want.
1213 //
1214 // We only want to replace whatever the default constructor put there, if we
1215 // have something meaningful to add.
1216
1217 STRINGREF s = StringObject::NewString(message);
1218 ((EXCEPTIONREF)throwable)->SetMessage(s);
1219 }
1220
1221 GCPROTECT_END();
1222
1223 return throwable;
1224#endif
1225}
1226
1227RuntimeExceptionKind EEException::GetKindFromHR(HRESULT hr, bool fIsWinRtMode /*= false*/)
1228{
1229 LIMITED_METHOD_CONTRACT;
1230
1231 #ifdef FEATURE_COMINTEROP
1232 // If we are in WinRT mode, try to get a WinRT specific mapping first:
1233 if (fIsWinRtMode)
1234 {
1235 for (int i = 0; i < kWinRtExLastException; i++)
1236 {
1237 for (int j = 0; j < gWinRtHR_to_ExceptionKind_Maps[i].cHRs; j++)
1238 {
1239 if (gWinRtHR_to_ExceptionKind_Maps[i].aHRs[j] == hr)
1240 {
1241 return gWinRtHR_to_ExceptionKind_Maps[i].reKind;
1242 }
1243 }
1244 }
1245 }
1246 #endif // FEATURE_COMINTEROP
1247
1248 // Is not in WinRT mode OR did not find a WinRT specific mapping. Check normal mappings:
1249
1250 for (int i = 0; i < kLastException; i++)
1251 {
1252 for (int j = 0; j < gExceptionHRInfos[i].cHRs; j++)
1253 {
1254 if (gExceptionHRInfos[i].aHRs[j] == hr)
1255 return (RuntimeExceptionKind) i;
1256 }
1257 }
1258
1259 return (fIsWinRtMode ? kException : kCOMException);
1260
1261} // RuntimeExceptionKind EEException::GetKindFromHR()
1262
1263BOOL EEException::GetResourceMessage(UINT iResourceID, SString &result,
1264 const SString &arg1, const SString &arg2,
1265 const SString &arg3, const SString &arg4,
1266 const SString &arg5, const SString &arg6)
1267{
1268 CONTRACTL
1269 {
1270 GC_TRIGGERS;
1271 THROWS;
1272 MODE_ANY;
1273 }
1274 CONTRACTL_END;
1275
1276 BOOL ok;
1277
1278 StackSString temp;
1279 ok = temp.LoadResource(CCompRC::Error, iResourceID);
1280
1281 if (ok)
1282 result.FormatMessage(FORMAT_MESSAGE_FROM_STRING,
1283 (LPCWSTR)temp, 0, 0, arg1, arg2, arg3, arg4, arg5, arg6);
1284
1285 return ok;
1286}
1287
1288// ---------------------------------------------------------------------------
1289// EEMessageException methods
1290// ---------------------------------------------------------------------------
1291
1292HRESULT EEMessageException::GetHR()
1293{
1294 WRAPPER_NO_CONTRACT;
1295
1296 return m_hr;
1297}
1298
1299BOOL EEMessageException::GetThrowableMessage(SString &result)
1300{
1301 CONTRACTL
1302 {
1303 GC_TRIGGERS;
1304 THROWS;
1305 MODE_ANY;
1306 }
1307 CONTRACTL_END;
1308
1309 if (m_resID != 0 && GetResourceMessage(m_resID, result))
1310 return TRUE;
1311
1312 return EEException::GetThrowableMessage(result);
1313}
1314
1315BOOL EEMessageException::GetResourceMessage(UINT iResourceID, SString &result)
1316{
1317 WRAPPER_NO_CONTRACT;
1318
1319 return EEException::GetResourceMessage(
1320 iResourceID, result, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6);
1321}
1322
1323// ---------------------------------------------------------------------------
1324// EEResourceException methods
1325// ---------------------------------------------------------------------------
1326
1327void EEResourceException::GetMessage(SString &result)
1328{
1329 WRAPPER_NO_CONTRACT;
1330 //
1331 // Return a simplified message,
1332 // since we don't want to call managed code here.
1333 //
1334
1335 result.Printf("%s (message resource %s)",
1336 MscorlibBinder::GetExceptionName(m_kind), m_resourceName.GetUnicode());
1337}
1338
1339BOOL EEResourceException::GetThrowableMessage(SString &result)
1340{
1341 CONTRACTL
1342 {
1343 GC_TRIGGERS;
1344 THROWS;
1345 MODE_COOPERATIVE;
1346 }
1347 CONTRACTL_END;
1348
1349#ifndef CROSSGEN_COMPILE
1350 STRINGREF message = NULL;
1351 ResMgrGetString(m_resourceName, &message);
1352
1353 if (message != NULL)
1354 {
1355 message->GetSString(result);
1356 return TRUE;
1357 }
1358#endif // CROSSGEN_COMPILE
1359
1360 return EEException::GetThrowableMessage(result);
1361}
1362
1363// ---------------------------------------------------------------------------
1364// EEFieldException is an EE exception subclass composed of a field
1365// ---------------------------------------------------------------------------
1366
1367
1368BOOL EEFieldException::GetThrowableMessage(SString &result)
1369{
1370 CONTRACTL
1371 {
1372 GC_TRIGGERS;
1373 THROWS;
1374 MODE_ANY;
1375 }
1376 CONTRACTL_END;
1377
1378 if (m_messageID == 0)
1379 {
1380 LPUTF8 szFullName;
1381 LPCUTF8 szClassName, szMember;
1382 szMember = m_pFD->GetName();
1383 DefineFullyQualifiedNameForClass();
1384 szClassName = GetFullyQualifiedNameForClass(m_pFD->GetApproxEnclosingMethodTable());
1385 MAKE_FULLY_QUALIFIED_MEMBER_NAME(szFullName, NULL, szClassName, szMember, "");
1386 result.SetUTF8(szFullName);
1387
1388 return TRUE;
1389 }
1390 else
1391 {
1392 _ASSERTE(m_pAccessingMD != NULL);
1393
1394 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1395 TypeString::FormatNamespace |
1396 TypeString::FormatAngleBrackets |
1397 TypeString::FormatSignature);
1398
1399 StackSString caller;
1400 TypeString::AppendMethod(caller,
1401 m_pAccessingMD,
1402 m_pAccessingMD->GetClassInstantiation(),
1403 formatFlags);
1404
1405 StackSString field;
1406 TypeString::AppendField(field,
1407 m_pFD,
1408 m_pFD->GetApproxEnclosingMethodTable()->GetInstantiation(),
1409 formatFlags);
1410
1411 return GetResourceMessage(m_messageID, result, caller, field, m_additionalContext);
1412 }
1413}
1414
1415// ---------------------------------------------------------------------------
1416// EEMethodException is an EE exception subclass composed of a field
1417// ---------------------------------------------------------------------------
1418
1419BOOL EEMethodException::GetThrowableMessage(SString &result)
1420{
1421 CONTRACTL
1422 {
1423 GC_TRIGGERS;
1424 THROWS;
1425 MODE_ANY;
1426 }
1427 CONTRACTL_END;
1428
1429 if (m_messageID == 0)
1430 {
1431 LPUTF8 szFullName;
1432 LPCUTF8 szClassName, szMember;
1433 szMember = m_pMD->GetName();
1434 DefineFullyQualifiedNameForClass();
1435 szClassName = GetFullyQualifiedNameForClass(m_pMD->GetMethodTable());
1436 //@todo GENERICS: exact instantiations?
1437 MetaSig tmp(m_pMD);
1438 SigFormat sigFormatter(tmp, szMember);
1439 const char * sigStr = sigFormatter.GetCStringParmsOnly();
1440 MAKE_FULLY_QUALIFIED_MEMBER_NAME(szFullName, NULL, szClassName, szMember, sigStr);
1441 result.SetUTF8(szFullName);
1442
1443 return TRUE;
1444 }
1445 else
1446 {
1447 _ASSERTE(m_pAccessingMD != NULL);
1448
1449 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1450 TypeString::FormatNamespace |
1451 TypeString::FormatAngleBrackets |
1452 TypeString::FormatSignature);
1453
1454 StackSString caller;
1455 TypeString::AppendMethod(caller,
1456 m_pAccessingMD,
1457 m_pAccessingMD->GetClassInstantiation(),
1458 formatFlags);
1459
1460 StackSString callee;
1461 TypeString::AppendMethod(callee,
1462 m_pMD,
1463 m_pMD->GetClassInstantiation(),
1464 formatFlags);
1465
1466 return GetResourceMessage(m_messageID, result, caller, callee, m_additionalContext);
1467 }
1468}
1469
1470BOOL EETypeAccessException::GetThrowableMessage(SString &result)
1471{
1472 CONTRACTL
1473 {
1474 GC_TRIGGERS;
1475 THROWS;
1476 MODE_ANY;
1477 }
1478 CONTRACTL_END;
1479
1480 const TypeString::FormatFlags formatFlags = static_cast<TypeString::FormatFlags>(
1481 TypeString::FormatNamespace |
1482 TypeString::FormatAngleBrackets |
1483 TypeString::FormatSignature);
1484 StackSString type;
1485 TypeString::AppendType(type, TypeHandle(m_pMT), formatFlags);
1486
1487 if (m_messageID == 0)
1488 {
1489 result.Set(type);
1490 return TRUE;
1491 }
1492 else
1493 {
1494 _ASSERTE(m_pAccessingMD != NULL);
1495
1496 StackSString caller;
1497 TypeString::AppendMethod(caller,
1498 m_pAccessingMD,
1499 m_pAccessingMD->GetClassInstantiation(),
1500 formatFlags);
1501
1502 return GetResourceMessage(m_messageID, result, caller, type, m_additionalContext);
1503 }
1504}
1505
1506// ---------------------------------------------------------------------------
1507// EEArgumentException is an EE exception subclass representing a bad argument
1508// ---------------------------------------------------------------------------
1509
1510typedef struct {
1511 OBJECTREF pThrowable;
1512 STRINGREF s1;
1513 OBJECTREF pTmpThrowable;
1514} ProtectArgsStruct;
1515
1516OBJECTREF EEArgumentException::CreateThrowable()
1517{
1518#ifdef CROSSGEN_COMPILE
1519 _ASSERTE(false);
1520 return NULL;
1521#else
1522
1523 CONTRACTL
1524 {
1525 GC_TRIGGERS;
1526 THROWS;
1527 MODE_COOPERATIVE;
1528 }
1529 CONTRACTL_END;
1530
1531 _ASSERTE(GetThread() != NULL);
1532
1533 ProtectArgsStruct prot;
1534 memset(&prot, 0, sizeof(ProtectArgsStruct));
1535 ResMgrGetString(m_resourceName, &prot.s1);
1536 GCPROTECT_BEGIN(prot);
1537
1538 MethodTable *pMT = MscorlibBinder::GetException(m_kind);
1539 prot.pThrowable = AllocateObject(pMT);
1540
1541 MethodDesc* pMD = MemberLoader::FindMethod(prot.pThrowable->GetMethodTable(),
1542 COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_RetVoid);
1543
1544 if (!pMD)
1545 {
1546 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1547 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1548 }
1549
1550 MethodDescCallSite exceptionCtor(pMD);
1551
1552 STRINGREF argName = StringObject::NewString(m_argumentName);
1553
1554 // Note that ArgumentException takes arguments to its constructor in a different order,
1555 // for usability reasons. However it is inconsistent with our other exceptions.
1556 if (m_kind == kArgumentException)
1557 {
1558 ARG_SLOT args1[] = {
1559 ObjToArgSlot(prot.pThrowable),
1560 ObjToArgSlot(prot.s1),
1561 ObjToArgSlot(argName),
1562 };
1563 exceptionCtor.Call(args1);
1564 }
1565 else
1566 {
1567 ARG_SLOT args1[] = {
1568 ObjToArgSlot(prot.pThrowable),
1569 ObjToArgSlot(argName),
1570 ObjToArgSlot(prot.s1),
1571 };
1572 exceptionCtor.Call(args1);
1573 }
1574
1575 GCPROTECT_END(); //Prot
1576
1577 return prot.pThrowable;
1578#endif
1579}
1580
1581
1582// ---------------------------------------------------------------------------
1583// EETypeLoadException is an EE exception subclass representing a type loading
1584// error
1585// ---------------------------------------------------------------------------
1586
1587EETypeLoadException::EETypeLoadException(LPCUTF8 pszNameSpace, LPCUTF8 pTypeName,
1588 LPCWSTR pAssemblyName, LPCUTF8 pMessageArg, UINT resIDWhy)
1589 : EEException(kTypeLoadException),
1590 m_pAssemblyName(pAssemblyName),
1591 m_pMessageArg(SString::Utf8, pMessageArg),
1592 m_resIDWhy(resIDWhy)
1593{
1594 CONTRACTL
1595 {
1596 GC_NOTRIGGER;
1597 THROWS;
1598 MODE_ANY;
1599 }
1600 CONTRACTL_END;
1601
1602 if(pszNameSpace)
1603 {
1604 SString sNameSpace(SString::Utf8, pszNameSpace);
1605 SString sTypeName(SString::Utf8, pTypeName);
1606 m_fullName.MakeFullNamespacePath(sNameSpace, sTypeName);
1607 }
1608 else if (pTypeName)
1609 m_fullName.SetUTF8(pTypeName);
1610 else {
1611 WCHAR wszTemplate[30];
1612 if (FAILED(UtilLoadStringRC(IDS_EE_NAME_UNKNOWN,
1613 wszTemplate,
1614 sizeof(wszTemplate)/sizeof(wszTemplate[0]),
1615 FALSE)))
1616 wszTemplate[0] = W('\0');
1617 MAKE_UTF8PTR_FROMWIDE(name, wszTemplate);
1618 m_fullName.SetUTF8(name);
1619 }
1620}
1621
1622EETypeLoadException::EETypeLoadException(LPCWSTR pFullName,
1623 LPCWSTR pAssemblyName,
1624 LPCUTF8 pMessageArg,
1625 UINT resIDWhy)
1626 : EEException(kTypeLoadException),
1627 m_pAssemblyName(pAssemblyName),
1628 m_pMessageArg(SString::Utf8, pMessageArg),
1629 m_resIDWhy(resIDWhy)
1630{
1631 CONTRACTL
1632 {
1633 GC_NOTRIGGER;
1634 THROWS;
1635 MODE_ANY;
1636 }
1637 CONTRACTL_END;
1638
1639 MAKE_UTF8PTR_FROMWIDE(name, pFullName);
1640 m_fullName.SetUTF8(name);
1641}
1642
1643void EETypeLoadException::GetMessage(SString &result)
1644{
1645 WRAPPER_NO_CONTRACT;
1646 GetResourceMessage(IDS_CLASSLOAD_GENERAL, result,
1647 m_fullName, m_pAssemblyName, m_pMessageArg);
1648}
1649
1650OBJECTREF EETypeLoadException::CreateThrowable()
1651{
1652#ifdef CROSSGEN_COMPILE
1653 _ASSERTE(false);
1654 return NULL;
1655#else
1656
1657 CONTRACTL
1658 {
1659 GC_TRIGGERS;
1660 THROWS;
1661 MODE_COOPERATIVE;
1662 }
1663 CONTRACTL_END;
1664
1665 COUNTER_ONLY(GetPerfCounters().m_Loading.cLoadFailures++);
1666
1667 MethodTable *pMT = MscorlibBinder::GetException(kTypeLoadException);
1668
1669 struct _gc {
1670 OBJECTREF pNewException;
1671 STRINGREF pNewAssemblyString;
1672 STRINGREF pNewClassString;
1673 STRINGREF pNewMessageArgString;
1674 } gc;
1675 ZeroMemory(&gc, sizeof(gc));
1676 GCPROTECT_BEGIN(gc);
1677
1678 gc.pNewClassString = StringObject::NewString(m_fullName);
1679
1680 if (!m_pMessageArg.IsEmpty())
1681 gc.pNewMessageArgString = StringObject::NewString(m_pMessageArg);
1682
1683 if (!m_pAssemblyName.IsEmpty())
1684 gc.pNewAssemblyString = StringObject::NewString(m_pAssemblyName);
1685
1686 gc.pNewException = AllocateObject(pMT);
1687
1688 MethodDesc* pMD = MemberLoader::FindMethod(gc.pNewException->GetMethodTable(),
1689 COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_Str_Int_RetVoid);
1690
1691 if (!pMD)
1692 {
1693 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1694 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1695 }
1696
1697 MethodDescCallSite exceptionCtor(pMD);
1698
1699 ARG_SLOT args[] = {
1700 ObjToArgSlot(gc.pNewException),
1701 ObjToArgSlot(gc.pNewClassString),
1702 ObjToArgSlot(gc.pNewAssemblyString),
1703 ObjToArgSlot(gc.pNewMessageArgString),
1704 (ARG_SLOT)m_resIDWhy,
1705 };
1706
1707 exceptionCtor.Call(args);
1708
1709 GCPROTECT_END();
1710
1711 return gc.pNewException;
1712#endif
1713}
1714
1715// ---------------------------------------------------------------------------
1716// EEFileLoadException is an EE exception subclass representing a file loading
1717// error
1718// ---------------------------------------------------------------------------
1719EEFileLoadException::EEFileLoadException(const SString &name, HRESULT hr, void *pFusionLog, Exception *pInnerException/* = NULL*/)
1720 : EEException(GetFileLoadKind(hr)),
1721 m_name(name),
1722 m_pFusionLog(pFusionLog),
1723 m_hr(hr)
1724{
1725 CONTRACTL
1726 {
1727 GC_NOTRIGGER;
1728 THROWS;
1729 MODE_ANY;
1730 }
1731 CONTRACTL_END;
1732
1733 // We don't want to wrap IsTransient() exceptions. The caller should really have checked this
1734 // before invoking the ctor.
1735 _ASSERTE(pInnerException == NULL || !(pInnerException->IsTransient()));
1736 m_innerException = pInnerException ? pInnerException->DomainBoundClone() : NULL;
1737
1738 if (m_name.IsEmpty())
1739 {
1740 WCHAR wszTemplate[30];
1741 if (FAILED(UtilLoadStringRC(IDS_EE_NAME_UNKNOWN,
1742 wszTemplate,
1743 sizeof(wszTemplate)/sizeof(wszTemplate[0]),
1744 FALSE)))
1745 {
1746 wszTemplate[0] = W('\0');
1747 }
1748
1749 m_name.Set(wszTemplate);
1750 }
1751}
1752
1753
1754EEFileLoadException::~EEFileLoadException()
1755{
1756 STATIC_CONTRACT_NOTHROW;
1757 STATIC_CONTRACT_GC_NOTRIGGER;
1758
1759}
1760
1761
1762
1763void EEFileLoadException::SetFileName(const SString &fileName, BOOL removePath)
1764{
1765 CONTRACTL
1766 {
1767 GC_NOTRIGGER;
1768 THROWS;
1769 MODE_ANY;
1770 }
1771 CONTRACTL_END;
1772
1773 //<TODO>@TODO: security: It would be nice for debugging purposes if the
1774 // user could have the full path, if the user has the right permission.</TODO>
1775 if (removePath)
1776 {
1777 SString::CIterator i = fileName.End();
1778
1779 if (fileName.FindBack(i, W('\\')))
1780 i++;
1781
1782 if (fileName.FindBack(i, W('/')))
1783 i++;
1784
1785 m_name.Set(fileName, i, fileName.End());
1786 }
1787 else
1788 m_name.Set(fileName);
1789}
1790
1791void EEFileLoadException::GetMessage(SString &result)
1792{
1793 WRAPPER_NO_CONTRACT;
1794
1795 SString sHR;
1796 GetHRMsg(m_hr, sHR);
1797 GetResourceMessage(GetResourceIDForFileLoadExceptionHR(m_hr), result, m_name, sHR);
1798}
1799
1800void EEFileLoadException::GetName(SString &result)
1801{
1802 WRAPPER_NO_CONTRACT;
1803
1804 result.Set(m_name);
1805}
1806
1807/* static */
1808RuntimeExceptionKind EEFileLoadException::GetFileLoadKind(HRESULT hr)
1809{
1810 CONTRACTL
1811 {
1812 GC_NOTRIGGER;
1813 NOTHROW;
1814 MODE_ANY;
1815 }
1816 CONTRACTL_END;
1817
1818 if (Assembly::FileNotFound(hr))
1819 return kFileNotFoundException;
1820 else
1821 {
1822 // Make sure this matches the list in rexcep.h
1823 if ((hr == COR_E_BADIMAGEFORMAT) ||
1824 (hr == CLDB_E_FILE_OLDVER) ||
1825 (hr == CLDB_E_INDEX_NOTFOUND) ||
1826 (hr == CLDB_E_FILE_CORRUPT) ||
1827 (hr == COR_E_NEWER_RUNTIME) ||
1828 (hr == COR_E_ASSEMBLYEXPECTED) ||
1829 (hr == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT)) ||
1830 (hr == HRESULT_FROM_WIN32(ERROR_EXE_MARKED_INVALID)) ||
1831 (hr == CORSEC_E_INVALID_IMAGE_FORMAT) ||
1832 (hr == HRESULT_FROM_WIN32(ERROR_NOACCESS)) ||
1833 (hr == HRESULT_FROM_WIN32(ERROR_INVALID_ORDINAL)) ||
1834 (hr == HRESULT_FROM_WIN32(ERROR_INVALID_DLL)) ||
1835 (hr == HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT)) ||
1836 (hr == (HRESULT) IDS_CLASSLOAD_32BITCLRLOADING64BITASSEMBLY) ||
1837 (hr == COR_E_LOADING_REFERENCE_ASSEMBLY) ||
1838 (hr == META_E_BAD_SIGNATURE) ||
1839 (hr == COR_E_LOADING_WINMD_REFERENCE_ASSEMBLY))
1840 return kBadImageFormatException;
1841 else
1842 {
1843 if ((hr == E_OUTOFMEMORY) || (hr == NTE_NO_MEMORY))
1844 return kOutOfMemoryException;
1845 else
1846 return kFileLoadException;
1847 }
1848 }
1849}
1850
1851OBJECTREF EEFileLoadException::CreateThrowable()
1852{
1853#ifdef CROSSGEN_COMPILE
1854 _ASSERTE(false);
1855 return NULL;
1856#else
1857
1858 CONTRACTL
1859 {
1860 GC_TRIGGERS;
1861 THROWS;
1862 MODE_COOPERATIVE;
1863 }
1864 CONTRACTL_END;
1865
1866 COUNTER_ONLY(GetPerfCounters().m_Loading.cLoadFailures++);
1867
1868 // Fetch any log info from the fusion log
1869 SString logText;
1870 struct _gc {
1871 OBJECTREF pNewException;
1872 STRINGREF pNewFileString;
1873 STRINGREF pFusLogString;
1874 } gc;
1875 ZeroMemory(&gc, sizeof(gc));
1876 GCPROTECT_BEGIN(gc);
1877
1878 gc.pNewFileString = StringObject::NewString(m_name);
1879 gc.pFusLogString = StringObject::NewString(logText);
1880 gc.pNewException = AllocateObject(MscorlibBinder::GetException(m_kind));
1881
1882 MethodDesc* pMD = MemberLoader::FindMethod(gc.pNewException->GetMethodTable(),
1883 COR_CTOR_METHOD_NAME, &gsig_IM_Str_Str_Int_RetVoid);
1884
1885 if (!pMD)
1886 {
1887 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
1888 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
1889 }
1890
1891 MethodDescCallSite exceptionCtor(pMD);
1892
1893 ARG_SLOT args[] = {
1894 ObjToArgSlot(gc.pNewException),
1895 ObjToArgSlot(gc.pNewFileString),
1896 ObjToArgSlot(gc.pFusLogString),
1897 (ARG_SLOT) m_hr
1898 };
1899
1900 exceptionCtor.Call(args);
1901
1902 GCPROTECT_END();
1903
1904 return gc.pNewException;
1905#endif
1906}
1907
1908
1909/* static */
1910BOOL EEFileLoadException::CheckType(Exception* ex)
1911{
1912 LIMITED_METHOD_CONTRACT;
1913
1914 // used as typeof(EEFileLoadException)
1915 RuntimeExceptionKind kind = kException;
1916 if (ex->IsType(EEException::GetType()))
1917 kind=((EEException*)ex)->m_kind;
1918
1919
1920 switch(kind)
1921 {
1922 case kFileLoadException:
1923 case kFileNotFoundException:
1924 case kBadImageFormatException:
1925 return TRUE;
1926 default:
1927 return FALSE;
1928 }
1929};
1930
1931
1932// <TODO>@todo: ideally we would use inner exceptions with these routines</TODO>
1933
1934/* static */
1935
1936/* static */
1937void DECLSPEC_NORETURN EEFileLoadException::Throw(AssemblySpec *pSpec, HRESULT hr, Exception *pInnerException/* = NULL*/)
1938{
1939 CONTRACTL
1940 {
1941 GC_TRIGGERS;
1942 THROWS;
1943 MODE_ANY;
1944 }
1945 CONTRACTL_END;
1946
1947 if (hr == COR_E_THREADABORTED)
1948 COMPlusThrow(kThreadAbortException);
1949 if (hr == E_OUTOFMEMORY)
1950 COMPlusThrowOM();
1951#ifdef FEATURE_COMINTEROP
1952 if ((hr == RO_E_METADATA_NAME_NOT_FOUND) || (hr == CLR_E_BIND_TYPE_NOT_FOUND))
1953 { // These error codes behave like FileNotFound, but are exposed as TypeLoadException
1954 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), pInnerException);
1955 }
1956#endif //FEATURE_COMINTEROP
1957
1958 StackSString name;
1959 pSpec->GetFileOrDisplayName(0, name);
1960 EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1961}
1962
1963/* static */
1964void DECLSPEC_NORETURN EEFileLoadException::Throw(PEFile *pFile, HRESULT hr, Exception *pInnerException /* = NULL*/)
1965{
1966 CONTRACTL
1967 {
1968 GC_TRIGGERS;
1969 THROWS;
1970 MODE_ANY;
1971 }
1972 CONTRACTL_END;
1973
1974 if (hr == COR_E_THREADABORTED)
1975 COMPlusThrow(kThreadAbortException);
1976 if (hr == E_OUTOFMEMORY)
1977 COMPlusThrowOM();
1978
1979 StackSString name;
1980
1981 if (pFile->IsAssembly())
1982 ((PEAssembly*)pFile)->GetDisplayName(name);
1983 else
1984 name = StackSString(SString::Utf8, pFile->GetSimpleName());
1985 EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
1986
1987}
1988
1989/* static */
1990void DECLSPEC_NORETURN EEFileLoadException::Throw(LPCWSTR path, HRESULT hr, Exception *pInnerException/* = NULL*/)
1991{
1992 CONTRACTL
1993 {
1994 GC_TRIGGERS;
1995 THROWS;
1996 MODE_ANY;
1997 }
1998 CONTRACTL_END;
1999
2000 if (hr == COR_E_THREADABORTED)
2001 COMPlusThrow(kThreadAbortException);
2002 if (hr == E_OUTOFMEMORY)
2003 COMPlusThrowOM();
2004
2005 EX_THROW_WITH_INNER(EEFileLoadException, (StackSString(path), hr), pInnerException);
2006}
2007
2008/* static */
2009/* static */
2010void DECLSPEC_NORETURN EEFileLoadException::Throw(PEAssembly *parent,
2011 const void *memory, COUNT_T size, HRESULT hr, Exception *pInnerException/* = NULL*/)
2012{
2013 CONTRACTL
2014 {
2015 GC_TRIGGERS;
2016 THROWS;
2017 MODE_ANY;
2018 }
2019 CONTRACTL_END;
2020
2021 if (hr == COR_E_THREADABORTED)
2022 COMPlusThrow(kThreadAbortException);
2023 if (hr == E_OUTOFMEMORY)
2024 COMPlusThrowOM();
2025
2026 StackSString name;
2027 name.Printf("%d bytes loaded from ", size);
2028
2029 StackSString parentName;
2030 parent->GetDisplayName(parentName);
2031
2032 name.Append(parentName);
2033 EX_THROW_WITH_INNER(EEFileLoadException, (name, hr), pInnerException);
2034}
2035
2036#ifndef CROSSGEN_COMPILE
2037// ---------------------------------------------------------------------------
2038// EEComException methods
2039// ---------------------------------------------------------------------------
2040
2041static HRESULT Undefer(EXCEPINFO *pExcepInfo)
2042{
2043 CONTRACTL
2044 {
2045 GC_NOTRIGGER;
2046 NOTHROW;
2047 MODE_ANY;
2048 }
2049 CONTRACTL_END;
2050
2051 if (pExcepInfo->pfnDeferredFillIn)
2052 {
2053 EXCEPINFO FilledInExcepInfo;
2054
2055 HRESULT hr = pExcepInfo->pfnDeferredFillIn(&FilledInExcepInfo);
2056 if (SUCCEEDED(hr))
2057 {
2058 // Free the strings in the original EXCEPINFO.
2059 if (pExcepInfo->bstrDescription)
2060 {
2061 SysFreeString(pExcepInfo->bstrDescription);
2062 pExcepInfo->bstrDescription = NULL;
2063 }
2064 if (pExcepInfo->bstrSource)
2065 {
2066 SysFreeString(pExcepInfo->bstrSource);
2067 pExcepInfo->bstrSource = NULL;
2068 }
2069 if (pExcepInfo->bstrHelpFile)
2070 {
2071 SysFreeString(pExcepInfo->bstrHelpFile);
2072 pExcepInfo->bstrHelpFile = NULL;
2073 }
2074
2075 // Fill in the new data
2076 *pExcepInfo = FilledInExcepInfo;
2077 }
2078 }
2079
2080 if (pExcepInfo->scode != 0)
2081 return pExcepInfo->scode;
2082 else
2083 return (HRESULT)pExcepInfo->wCode;
2084}
2085
2086EECOMException::EECOMException(EXCEPINFO *pExcepInfo)
2087 : EEException(GetKindFromHR(Undefer(pExcepInfo)))
2088{
2089 WRAPPER_NO_CONTRACT;
2090
2091 if (pExcepInfo->scode != 0)
2092 m_ED.hr = pExcepInfo->scode;
2093 else
2094 m_ED.hr = (HRESULT)pExcepInfo->wCode;
2095
2096 m_ED.bstrDescription = pExcepInfo->bstrDescription;
2097 m_ED.bstrSource = pExcepInfo->bstrSource;
2098 m_ED.bstrHelpFile = pExcepInfo->bstrHelpFile;
2099 m_ED.dwHelpContext = pExcepInfo->dwHelpContext;
2100 m_ED.guid = GUID_NULL;
2101
2102#ifdef FEATURE_COMINTEROP
2103 m_ED.bstrReference = NULL;
2104 m_ED.bstrRestrictedError = NULL;
2105 m_ED.bstrCapabilitySid = NULL;
2106 m_ED.pRestrictedErrorInfo = NULL;
2107 m_ED.bHasLanguageRestrictedErrorInfo = FALSE;
2108#endif
2109
2110 // Zero the EXCEPINFO.
2111 memset(pExcepInfo, NULL, sizeof(EXCEPINFO));
2112}
2113
2114EECOMException::EECOMException(ExceptionData *pData)
2115 : EEException(GetKindFromHR(pData->hr))
2116{
2117 LIMITED_METHOD_CONTRACT;
2118
2119 m_ED = *pData;
2120
2121 // Zero the data.
2122 ZeroMemory(pData, sizeof(ExceptionData));
2123}
2124
2125EECOMException::EECOMException(
2126 HRESULT hr,
2127 IErrorInfo *pErrInfo,
2128 bool fUseCOMException, // use System.Runtime.InteropServices.COMException as the default exception type (means as much as !IsWinRT)
2129 IRestrictedErrorInfo* pRestrictedErrInfo,
2130 BOOL bHasLanguageRestrictedErrInfo
2131 COMMA_INDEBUG(BOOL bCheckInProcCCWTearOff))
2132 : EEException(GetKindFromHR(hr, !fUseCOMException))
2133{
2134 WRAPPER_NO_CONTRACT;
2135
2136#ifdef FEATURE_COMINTEROP
2137 // Must use another path for managed IErrorInfos...
2138 // note that this doesn't cover out-of-proc managed IErrorInfos.
2139 _ASSERTE(!bCheckInProcCCWTearOff || !IsInProcCCWTearOff(pErrInfo));
2140 _ASSERTE(pRestrictedErrInfo == NULL || !bCheckInProcCCWTearOff || !IsInProcCCWTearOff(pRestrictedErrInfo));
2141#endif // FEATURE_COMINTEROP
2142
2143 m_ED.hr = hr;
2144 m_ED.bstrDescription = NULL;
2145 m_ED.bstrSource = NULL;
2146 m_ED.bstrHelpFile = NULL;
2147 m_ED.dwHelpContext = NULL;
2148 m_ED.guid = GUID_NULL;
2149
2150#ifdef FEATURE_COMINTEROP
2151 m_ED.bstrReference = NULL;
2152 m_ED.bstrRestrictedError = NULL;
2153 m_ED.bstrCapabilitySid = NULL;
2154 m_ED.pRestrictedErrorInfo = NULL;
2155 m_ED.bHasLanguageRestrictedErrorInfo = bHasLanguageRestrictedErrInfo;
2156#endif
2157
2158 FillExceptionData(&m_ED, pErrInfo, pRestrictedErrInfo);
2159}
2160
2161BOOL EECOMException::GetThrowableMessage(SString &result)
2162{
2163 CONTRACTL
2164 {
2165 GC_TRIGGERS;
2166 THROWS;
2167 MODE_ANY;
2168 }
2169 CONTRACTL_END;
2170
2171#ifdef FEATURE_COMINTEROP
2172 if (m_ED.bstrDescription != NULL || m_ED.bstrRestrictedError != NULL)
2173 {
2174 // For cross language WinRT exceptions, general information will be available in the bstrDescription,
2175 // which is populated from IErrorInfo::GetDescription and more specific information will be available
2176 // in the bstrRestrictedError which comes from the IRestrictedErrorInfo. If both are available, we
2177 // need to concatinate them to produce the final exception message.
2178
2179 result.Clear();
2180
2181 // If we have a restricted description, start our message with that
2182 if (m_ED.bstrDescription != NULL)
2183 {
2184 SString generalInformation(m_ED.bstrDescription, SysStringLen(m_ED.bstrDescription));
2185 result.Append(generalInformation);
2186
2187 // If we're also going to have a specific error message, append a newline to separate the two
2188 if (m_ED.bstrRestrictedError != NULL)
2189 {
2190 result.Append(W("\r\n"));
2191 }
2192 }
2193
2194 // If we have additional error information, attach it to the end of the string
2195 if (m_ED.bstrRestrictedError != NULL)
2196 {
2197 SString restrictedDescription(m_ED.bstrRestrictedError, SysStringLen(m_ED.bstrRestrictedError));
2198 result.Append(restrictedDescription);
2199 }
2200 }
2201#else // !FEATURE_COMINTEROP
2202 if (m_ED.bstrDescription != NULL)
2203 {
2204 result.Set(m_ED.bstrDescription, SysStringLen(m_ED.bstrDescription));
2205 }
2206#endif // FEATURE_COMINTEROP
2207 else
2208 {
2209 GenerateTopLevelHRExceptionMessage(GetHR(), result);
2210 }
2211
2212 return TRUE;
2213}
2214
2215EECOMException::~EECOMException()
2216{
2217 WRAPPER_NO_CONTRACT;
2218
2219 FreeExceptionData(&m_ED);
2220}
2221
2222HRESULT EECOMException::GetHR()
2223{
2224 LIMITED_METHOD_CONTRACT;
2225
2226 return m_ED.hr;
2227}
2228
2229OBJECTREF EECOMException::CreateThrowable()
2230{
2231 CONTRACTL
2232 {
2233 GC_TRIGGERS;
2234 THROWS;
2235 MODE_COOPERATIVE;
2236 }
2237 CONTRACTL_END;
2238
2239 OBJECTREF throwable = NULL;
2240 GCPROTECT_BEGIN(throwable);
2241
2242 // Note that this will pick up the message from GetThrowableMessage
2243 throwable = EEException::CreateThrowable();
2244
2245 // Set the _helpURL field in the exception.
2246 if (m_ED.bstrHelpFile)
2247 {
2248 // Create the help link from the help file and the help context.
2249 STRINGREF helpStr = NULL;
2250 if (m_ED.dwHelpContext != 0)
2251 {
2252 // We have a non 0 help context so use it to form the help link.
2253 SString strMessage;
2254 strMessage.Printf(W("%s#%d"), m_ED.bstrHelpFile, m_ED.dwHelpContext);
2255 helpStr = StringObject::NewString(strMessage);
2256 }
2257 else
2258 {
2259 // The help context is 0 so we simply use the help file to from the help link.
2260 helpStr = StringObject::NewString(m_ED.bstrHelpFile, SysStringLen(m_ED.bstrHelpFile));
2261 }
2262
2263 ((EXCEPTIONREF)throwable)->SetHelpURL(helpStr);
2264 }
2265
2266 // Set the Source field in the exception.
2267 STRINGREF sourceStr = NULL;
2268 if (m_ED.bstrSource)
2269 {
2270 sourceStr = StringObject::NewString(m_ED.bstrSource, SysStringLen(m_ED.bstrSource));
2271 }
2272 else
2273 {
2274 // for now set a null source
2275 sourceStr = StringObject::GetEmptyString();
2276 }
2277 ((EXCEPTIONREF)throwable)->SetSource(sourceStr);
2278
2279#ifdef FEATURE_COMINTEROP
2280 //
2281 // Support for WinRT interface IRestrictedErrorInfo
2282 //
2283 if (m_ED.pRestrictedErrorInfo)
2284 {
2285
2286 struct _gc {
2287 STRINGREF RestrictedErrorRef;
2288 STRINGREF ReferenceRef;
2289 STRINGREF RestrictedCapabilitySidRef;
2290 OBJECTREF RestrictedErrorInfoObjRef;
2291 } gc;
2292 ZeroMemory(&gc, sizeof(gc));
2293
2294 GCPROTECT_BEGIN(gc);
2295
2296 EX_TRY
2297 {
2298 gc.RestrictedErrorRef = StringObject::NewString(
2299 m_ED.bstrRestrictedError,
2300 SysStringLen(m_ED.bstrRestrictedError)
2301 );
2302 gc.ReferenceRef = StringObject::NewString(
2303 m_ED.bstrReference,
2304 SysStringLen(m_ED.bstrReference)
2305 );
2306
2307 gc.RestrictedCapabilitySidRef = StringObject::NewString(
2308 m_ED.bstrCapabilitySid,
2309 SysStringLen(m_ED.bstrCapabilitySid)
2310 );
2311
2312 // Convert IRestrictedErrorInfo into a managed object - don't care whether it is a RCW/CCW
2313 GetObjectRefFromComIP(
2314 &gc.RestrictedErrorInfoObjRef,
2315 m_ED.pRestrictedErrorInfo, // IUnknown *
2316 NULL, // ClassMT
2317 NULL, // ItfMT
2318 ObjFromComIP::CLASS_IS_HINT | ObjFromComIP::IGNORE_WINRT_AND_SKIP_UNBOXING
2319 );
2320
2321 //
2322 // Call Exception.AddExceptionDataForRestrictedErrorInfo and put error information
2323 // from IRestrictedErrorInfo on Exception.Data
2324 //
2325 MethodDescCallSite addExceptionDataForRestrictedErrorInfo(
2326 METHOD__EXCEPTION__ADD_EXCEPTION_DATA_FOR_RESTRICTED_ERROR_INFO,
2327 &throwable
2328 );
2329
2330 ARG_SLOT Args[] =
2331 {
2332 ObjToArgSlot(throwable),
2333 ObjToArgSlot(gc.RestrictedErrorRef),
2334 ObjToArgSlot(gc.ReferenceRef),
2335 ObjToArgSlot(gc.RestrictedCapabilitySidRef),
2336 ObjToArgSlot(gc.RestrictedErrorInfoObjRef),
2337 BoolToArgSlot(m_ED.bHasLanguageRestrictedErrorInfo)
2338 };
2339
2340 addExceptionDataForRestrictedErrorInfo.Call(Args);
2341
2342 }
2343 EX_CATCH
2344 {
2345 // IDictionary.Add may throw. Ignore all non terminal exceptions
2346 }
2347 EX_END_CATCH(RethrowTerminalExceptions)
2348
2349 GCPROTECT_END();
2350 }
2351#endif // FEATURE_COMINTEROP
2352
2353 GCPROTECT_END();
2354
2355
2356 return throwable;
2357}
2358
2359// ---------------------------------------------------------------------------
2360// ObjrefException methods
2361// ---------------------------------------------------------------------------
2362
2363ObjrefException::ObjrefException()
2364{
2365 LIMITED_METHOD_CONTRACT;
2366}
2367
2368ObjrefException::ObjrefException(OBJECTREF throwable)
2369{
2370 CONTRACTL
2371 {
2372 THROWS;
2373 GC_NOTRIGGER;
2374 MODE_ANY;
2375 }
2376 CONTRACTL_END;
2377
2378 SetThrowableHandle(GetAppDomain()->CreateHandle(throwable));
2379}
2380
2381// --------------------------------------------------------------------------------------------------------------------------------------
2382// ObjrefException and CLRLastThrownObjectException are never set as inner exception for an internal CLR exception.
2383// As a result, if we invoke DomainBoundClone against an exception, it will never reach these implementations.
2384// If someone does set them as inner, it will trigger contract violation - which is valid and should be fixed by whoever
2385// set them as inner since Exception::DomainBoundClone is implemented in utilcode that has to work outside the context of CLR and thus,
2386// should never trigger GC. This is also why GC_TRIGGERS is not supported in utilcode (refer to its definition in contracts.h).
2387// --------------------------------------------------------------------------------------------------------------------------------------
2388Exception *ObjrefException::DomainBoundCloneHelper()
2389{
2390 CONTRACTL
2391 {
2392 THROWS;
2393 GC_TRIGGERS;
2394 MODE_ANY;
2395 }
2396 CONTRACTL_END;
2397 GCX_COOP();
2398 return new ObjrefException(GetThrowable());
2399}
2400
2401// ---------------------------------------------------------------------------
2402// CLRLastThrownException methods
2403// ---------------------------------------------------------------------------
2404
2405CLRLastThrownObjectException::CLRLastThrownObjectException()
2406{
2407 LIMITED_METHOD_CONTRACT;
2408}
2409
2410Exception *CLRLastThrownObjectException::CloneHelper()
2411 {
2412 WRAPPER_NO_CONTRACT;
2413 GCX_COOP();
2414 return new ObjrefException(GetThrowable());
2415}
2416
2417// ---------------------------------------------------------------------------
2418// See ObjrefException::DomainBoundCloneHelper comments.
2419// ---------------------------------------------------------------------------
2420Exception *CLRLastThrownObjectException::DomainBoundCloneHelper()
2421{
2422 CONTRACTL
2423 {
2424 THROWS;
2425 GC_TRIGGERS;
2426 MODE_ANY;
2427 }
2428 CONTRACTL_END;
2429 GCX_COOP();
2430 return new ObjrefException(GetThrowable());
2431}
2432
2433OBJECTREF CLRLastThrownObjectException::CreateThrowable()
2434{
2435 CONTRACTL
2436 {
2437 NOTHROW;
2438 GC_NOTRIGGER;
2439 MODE_COOPERATIVE;
2440 }
2441 CONTRACTL_END;
2442
2443 DEBUG_STMT(Validate());
2444
2445 return GetThread()->LastThrownObject();
2446} // OBJECTREF CLRLastThrownObjectException::CreateThrowable()
2447
2448#if defined(_DEBUG)
2449CLRLastThrownObjectException* CLRLastThrownObjectException::Validate()
2450{
2451 CONTRACTL {
2452 NOTHROW;
2453 GC_NOTRIGGER;
2454 DEBUG_ONLY;
2455 }
2456 CONTRACTL_END;
2457
2458 // Have to be in coop for GCPROTECT_BEGIN.
2459 GCX_COOP();
2460
2461 OBJECTREF throwable = NULL;
2462
2463 GCPROTECT_BEGIN(throwable);
2464
2465 Thread * pThread = GetThread();
2466 throwable = pThread->LastThrownObject();
2467
2468 DWORD dwCurrentExceptionCode = GetCurrentExceptionCode();
2469
2470 if (dwCurrentExceptionCode == BOOTUP_EXCEPTION_COMPLUS)
2471 {
2472 // BOOTUP_EXCEPTION_COMPLUS can be thrown when a thread setup is failed due to reasons like
2473 // runtime is being shutdown or managed code is no longer allowed to be executed.
2474 //
2475 // If this exception is caught in EX_CATCH, there may not be any LTO setup since:
2476 //
2477 // 1) It is setup against the thread that may not exist (due to thread setup failure)
2478 // 2) This exception is raised using RaiseException (and not the managed raise implementation in RaiseTheExceptionInternalOnly)
2479 // since managed code may not be allowed to be executed.
2480 //
2481 // However, code inside EX_CATCH is abstracted of this specificity of EH and thus, will attempt to fetch the throwble
2482 // using GET_THROWABLE that will, in turn, use the GET_EXCEPTION macro to fetch the C++ exception type corresponding to the caught exception.
2483 // Since BOOTUP_EXCEPTION_COMPLUS is a SEH exception, this (C++ exception) type will be CLRLastThrownObjectException.
2484 //
2485 // 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
2486 // that by the time a SEH exception is caught in EX_CATCH, the LTO is setup:
2487 //
2488 // A) For a managed exception thrown, this is done by RaiseTheExceptionInternalOnly.
2489 // 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
2490 // using CreateCOMPlusExceptionObject.
2491
2492 // Clearly, BOOTUP_EXCEPTION_COMPLUS can also be caught in EX_CATCH. However:
2493 //
2494 // (A) above is not applicable since the exception is raised using RaiseException.
2495 //
2496 // (B) scenario is interesting. On x86, CPFH_FirstPassHandler also invokes CLRVectoredExceptionHandler (for legacy purposes) that, in Phase3, will return EXCEPTION_CONTINUE_SEARCH for
2497 // BOOTUP_EXCEPTION_COMPLUS. This will result in CPFH_FirstPassHandler to simply return from the x86 personality routine without invoking CreateCOMPlusExceptionObject even if managed
2498 // frames were present on the stack (as happens in PInvoke). Thus, there is no LTO setup for X86.
2499 //
2500 // 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.
2501 // 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
2502 // 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.
2503 //
2504 // Thus, when we see BOOTUP_EXCEPTION_COMPLUS, we will return back successfully (without doing anything) to imply a successful LTO validation. Eventually, a valid
2505 // throwable will be returned to the user of GET_THROWABLE (for details, trace the call to CLRException::GetThrowableFromException for CLRLastThrownObjectException type).
2506 //
2507 // 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.
2508 }
2509 else if (throwable == NULL)
2510 { // If there isn't a LastThrownObject at all, that's a problem for GetLastThrownObject
2511 // We've lost track of the exception's type. Raise an assert. (This is configurable to allow
2512 // stress labs to turn off the assert.)
2513
2514 static int iSuppress = -1;
2515 if (iSuppress == -1)
2516 iSuppress = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuppressLostExceptionTypeAssert);
2517 if (!iSuppress)
2518 {
2519 // Raising an assert message can cause a mode violation.
2520 CONTRACT_VIOLATION(ModeViolation);
2521
2522 // Use DbgAssertDialog to get the formatting right.
2523 DbgAssertDialog(__FILE__, __LINE__,
2524 "The 'LastThrownObject' should not be, but is, NULL.\n"
2525 "The runtime may have lost track of the type of an exception in flight.\n"
2526 "Please get a good stack trace, find the caller of Validate, and file a bug against the owner.\n\n"
2527 "To suppress this assert 'set COMPlus_SuppressLostExceptionTypeAssert=1'");
2528 }
2529 }
2530
2531 GCPROTECT_END();
2532
2533 return this;
2534} // CLRLastThrownObjectException* CLRLastThrownObjectException::Validate()
2535#endif // _DEBUG
2536
2537// ---------------------------------------------------------------------------
2538// Helper function to get an exception from outside the exception.
2539// Create and return a LastThrownObjectException. Its virtual destructor
2540// will clean up properly.
2541void GetLastThrownObjectExceptionFromThread_Internal(Exception **ppException)
2542{
2543 CONTRACTL
2544 {
2545 GC_TRIGGERS;
2546 THROWS;
2547 MODE_ANY;
2548 SO_TOLERANT; // no risk of an SO after we've allocated the object here
2549 }
2550 CONTRACTL_END;
2551
2552 // If the Thread has been set up, then the LastThrownObject may make sense...
2553 if (GetThread())
2554 {
2555 // give back an object that knows about Threads and their exceptions.
2556 *ppException = new CLRLastThrownObjectException();
2557 }
2558 else
2559 {
2560 // but if no Thread, don't pretend to know about LastThrownObject.
2561 *ppException = NULL;
2562 }
2563
2564} // void GetLastThrownObjectExceptionFromThread_Internal()
2565
2566#endif // CROSSGEN_COMPILE
2567
2568//@TODO: Make available generally?
2569// Wrapper class to encapsulate both array pointer and element count.
2570template <typename T>
2571class ArrayReference
2572{
2573public:
2574 typedef T value_type;
2575 typedef const typename std::remove_const<T>::type const_value_type;
2576
2577 typedef ArrayDPTR(value_type) array_type;
2578 typedef ArrayDPTR(const_value_type) const_array_type;
2579
2580 // Constructor taking array pointer and size.
2581 ArrayReference(array_type array, size_t size)
2582 : _array(dac_cast<array_type>(array))
2583 , _size(size)
2584 { LIMITED_METHOD_CONTRACT; }
2585
2586 // Constructor taking a statically sized array by reference.
2587 template <size_t N>
2588 ArrayReference(T (&array)[N])
2589 : _array(dac_cast<array_type>(&array[0]))
2590 , _size(N)
2591 { LIMITED_METHOD_CONTRACT; }
2592
2593 // Copy constructor.
2594 ArrayReference(ArrayReference const & other)
2595 : _array(other._array)
2596 , _size(other._size)
2597 { LIMITED_METHOD_CONTRACT; }
2598
2599 // Indexer
2600 template <typename IdxT>
2601 T & operator[](IdxT idx)
2602 { LIMITED_METHOD_CONTRACT; _ASSERTE(idx < _size); return _array[idx]; }
2603
2604 // Implicit conversion operators.
2605 operator array_type()
2606 { LIMITED_METHOD_CONTRACT; return _array; }
2607
2608 operator const_array_type() const
2609 { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array); }
2610
2611 // Returns the array element count.
2612 size_t size() const
2613 { LIMITED_METHOD_CONTRACT; return _size; }
2614
2615 // Iteration methods and types.
2616 typedef array_type iterator;
2617
2618 iterator begin()
2619 { LIMITED_METHOD_CONTRACT; return _array; }
2620
2621 iterator end()
2622 { LIMITED_METHOD_CONTRACT; return _array + _size; }
2623
2624 typedef const_array_type const_iterator;
2625
2626 const_iterator begin() const
2627 { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array); }
2628
2629 const_iterator end() const
2630 { LIMITED_METHOD_CONTRACT; return dac_cast<const_array_type>(_array) + _size; }
2631
2632private:
2633 array_type _array;
2634 size_t _size;
2635};
2636
2637ArrayReference<const HRESULT> GetHRESULTsForExceptionKind(RuntimeExceptionKind kind)
2638{
2639 LIMITED_METHOD_CONTRACT;
2640
2641 switch (kind)
2642 {
2643 #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) \
2644 case k##reKind: \
2645 return ArrayReference<const HRESULT>(s_##reKind##HRs); \
2646 break;
2647 #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...)
2648 #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__)
2649 #include "rexcep.h"
2650
2651 default:
2652 _ASSERTE(!"Unknown exception kind!");
2653 break;
2654
2655 }
2656
2657 return ArrayReference<const HRESULT>(nullptr, 0);
2658}
2659
2660bool IsHRESULTForExceptionKind(HRESULT hr, RuntimeExceptionKind kind)
2661{
2662 LIMITED_METHOD_CONTRACT;
2663
2664 ArrayReference<const HRESULT> rgHR = GetHRESULTsForExceptionKind(kind);
2665 for (ArrayReference<const HRESULT>::iterator i = rgHR.begin(); i != rgHR.end(); ++i)
2666 {
2667 if (*i == hr)
2668 {
2669 return true;
2670 }
2671 }
2672
2673 return false;
2674}
2675
2676
2677