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.h |
9 | // --------------------------------------------------------------------------- |
10 | |
11 | |
12 | #ifndef _CLREX_H_ |
13 | #define _CLREX_H_ |
14 | |
15 | #include <ex.h> |
16 | |
17 | #include "runtimeexceptionkind.h" |
18 | #include "interoputil.h" |
19 | |
20 | class BaseBind; |
21 | class AssemblySpec; |
22 | class PEFile; |
23 | class PEAssembly; |
24 | |
25 | struct StackTraceElement |
26 | { |
27 | UINT_PTR ip; |
28 | UINT_PTR sp; |
29 | PTR_MethodDesc pFunc; |
30 | // TRUE if this element represents the last frame of the foreign |
31 | // exception stack trace. |
32 | BOOL fIsLastFrameFromForeignStackTrace; |
33 | |
34 | bool operator==(StackTraceElement const & rhs) const |
35 | { |
36 | return ip == rhs.ip |
37 | && sp == rhs.sp |
38 | && pFunc == rhs.pFunc; |
39 | } |
40 | |
41 | bool operator!=(StackTraceElement const & rhs) const |
42 | { |
43 | return !(*this == rhs); |
44 | } |
45 | }; |
46 | |
47 | class StackTraceInfo |
48 | { |
49 | private: |
50 | // for building stack trace info |
51 | StackTraceElement* m_pStackTrace; // pointer to stack trace storage |
52 | unsigned m_cStackTrace; // size of stack trace storage |
53 | unsigned m_dFrameCount; // current frame in stack trace |
54 | unsigned m_cDynamicMethodItems; // number of items in the Dynamic Method array |
55 | unsigned m_dCurrentDynamicIndex; // index of the next location where the resolver object will be stored |
56 | |
57 | public: |
58 | void Init(); |
59 | BOOL IsEmpty(); |
60 | void AllocateStackTrace(); |
61 | void ClearStackTrace(); |
62 | void FreeStackTrace(); |
63 | void SaveStackTrace(BOOL bAllowAllocMem, OBJECTHANDLE hThrowable, BOOL bReplaceStack, BOOL bSkipLastElement); |
64 | BOOL AppendElement(BOOL bAllowAllocMem, UINT_PTR currentIP, UINT_PTR currentSP, MethodDesc* pFunc, CrawlFrame* pCf); |
65 | |
66 | void GetLeafFrameInfo(StackTraceElement* pStackTraceElement); |
67 | }; |
68 | |
69 | |
70 | // --------------------------------------------------------------------------- |
71 | // CLRException represents an exception which has a managed representation. |
72 | // It adds the generic method GetThrowable(). |
73 | // --------------------------------------------------------------------------- |
74 | class CLRException : public Exception |
75 | { |
76 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
77 | friend class CLRLastThrownObjectException; |
78 | private: |
79 | static const int c_type = 0x434c5220; // 'CLR ' |
80 | |
81 | protected: |
82 | OBJECTHANDLE m_throwableHandle; |
83 | |
84 | void SetThrowableHandle(OBJECTHANDLE throwable); |
85 | OBJECTHANDLE GetThrowableHandle() { return m_throwableHandle; } |
86 | |
87 | |
88 | CLRException(); |
89 | public: |
90 | ~CLRException(); |
91 | |
92 | OBJECTREF GetThrowable(); |
93 | |
94 | // Dynamic type query for catchers |
95 | static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; } |
96 | virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; } |
97 | BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || Exception::IsType(type); } |
98 | |
99 | BOOL IsSameInstanceType(Exception *pException) |
100 | { |
101 | STATIC_CONTRACT_MODE_COOPERATIVE; |
102 | STATIC_CONTRACT_GC_TRIGGERS; |
103 | STATIC_CONTRACT_NOTHROW; |
104 | |
105 | if (pException->GetInstanceType() != GetInstanceType()) |
106 | { |
107 | return FALSE; |
108 | } |
109 | OBJECTREF mine = GetThrowable(); |
110 | OBJECTREF other = ((CLRException*)pException)->GetThrowable(); |
111 | return mine != NULL && other != NULL && |
112 | mine->GetMethodTable() == other->GetMethodTable(); |
113 | } |
114 | |
115 | // Overrides |
116 | virtual BOOL IsDomainBound() |
117 | { |
118 | //@TODO special case for preallocated exceptions? |
119 | return TRUE; |
120 | } |
121 | |
122 | HRESULT GetHR(); |
123 | IErrorInfo *GetErrorInfo(); |
124 | HRESULT SetErrorInfo(); |
125 | |
126 | void GetMessage(SString &result); |
127 | |
128 | protected: |
129 | |
130 | virtual OBJECTREF CreateThrowable() { LIMITED_METHOD_CONTRACT; return NULL; } |
131 | |
132 | public: // These are really private, but are used by the exception macros |
133 | |
134 | |
135 | // Accessors for all the preallocated exception objects. |
136 | static OBJECTREF GetPreallocatedBaseException(); |
137 | static OBJECTREF GetPreallocatedOutOfMemoryException(); |
138 | static OBJECTREF GetPreallocatedRudeThreadAbortException(); |
139 | static OBJECTREF GetPreallocatedThreadAbortException(); |
140 | static OBJECTREF GetPreallocatedStackOverflowException(); |
141 | static OBJECTREF GetPreallocatedExecutionEngineException(); |
142 | |
143 | // Accessors for all the preallocated exception handles. |
144 | static OBJECTHANDLE GetPreallocatedOutOfMemoryExceptionHandle(); |
145 | static OBJECTHANDLE GetPreallocatedRudeThreadAbortExceptionHandle(); |
146 | static OBJECTHANDLE GetPreallocatedThreadAbortExceptionHandle(); |
147 | static OBJECTHANDLE GetPreallocatedStackOverflowExceptionHandle(); |
148 | static OBJECTHANDLE GetPreallocatedExecutionEngineExceptionHandle(); |
149 | static OBJECTHANDLE GetPreallocatedHandleForObject(OBJECTREF o); |
150 | |
151 | // Use these to determine if a handle or object ref is one of the preallocated handles or object refs. |
152 | static BOOL IsPreallocatedExceptionObject(OBJECTREF o); |
153 | static BOOL IsPreallocatedExceptionHandle(OBJECTHANDLE h); |
154 | |
155 | // Prefer a new OOM exception if we can make one. If we cannot, then give back the pre-allocated |
156 | // one. |
157 | static OBJECTREF GetBestOutOfMemoryException(); |
158 | |
159 | static OBJECTREF GetThrowableFromException(Exception *pException); |
160 | static OBJECTREF GetThrowableFromExceptionRecord(EXCEPTION_RECORD *pExceptionRecord); |
161 | |
162 | class HandlerState : public Exception::HandlerState |
163 | { |
164 | public: |
165 | Thread* m_pThread; |
166 | Frame* m_pFrame; |
167 | BOOL m_fPreemptiveGCDisabled; |
168 | |
169 | enum NonNullThread |
170 | { |
171 | ThreadIsNotNull |
172 | }; |
173 | |
174 | HandlerState(Thread * pThread); |
175 | HandlerState(Thread * pThread, NonNullThread dummy); |
176 | |
177 | void CleanupTry(); |
178 | void SetupCatch(INDEBUG_COMMA(__in_z const char * szFile) int lineNum); |
179 | #ifdef LOGGING // Use parent implementation that inlines into nothing in retail build |
180 | void SucceedCatch(); |
181 | #endif |
182 | void SetupFinally(); |
183 | }; |
184 | }; |
185 | |
186 | // prototype for helper function to get exception object from thread's LastThrownObject. |
187 | void GetLastThrownObjectExceptionFromThread_Internal(Exception **ppException); |
188 | |
189 | |
190 | // --------------------------------------------------------------------------- |
191 | // EEException is a CLR exception subclass which has purely unmanaged representation. |
192 | // The standard methods will not do any GC dangerous operations. Thus you |
193 | // can throw and catch such an exception without regard to GC mode. |
194 | // --------------------------------------------------------------------------- |
195 | |
196 | class EEException : public CLRException |
197 | { |
198 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
199 | |
200 | private: |
201 | static const int c_type = 0x45452020; // 'EE ' |
202 | |
203 | public: |
204 | const RuntimeExceptionKind m_kind; |
205 | |
206 | EEException(RuntimeExceptionKind kind); |
207 | EEException(HRESULT hr); |
208 | |
209 | // Dynamic type query for catchers |
210 | static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; } |
211 | virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; } |
212 | BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || CLRException::IsType(type); } |
213 | |
214 | BOOL IsSameInstanceType(Exception *pException) |
215 | { |
216 | WRAPPER_NO_CONTRACT; |
217 | return pException->GetInstanceType() == GetType() && ((EEException*)pException)->m_kind == m_kind; |
218 | } |
219 | |
220 | // Virtual overrides |
221 | HRESULT GetHR(); |
222 | IErrorInfo *GetErrorInfo(); |
223 | void GetMessage(SString &result); |
224 | OBJECTREF CreateThrowable(); |
225 | |
226 | // GetThrowableMessage returns a message to be stored in the throwable. |
227 | // Returns FALSE if there is no useful value. |
228 | virtual BOOL GetThrowableMessage(SString &result); |
229 | |
230 | static BOOL GetResourceMessage(UINT iResourceID, SString &result, |
231 | const SString &arg1 = SString::Empty(), const SString &arg2 = SString::Empty(), |
232 | const SString &arg3 = SString::Empty(), const SString &arg4 = SString::Empty(), |
233 | const SString &arg5 = SString::Empty(), const SString &arg6 = SString::Empty()); |
234 | |
235 | // Note: reKind-->hr is a one-to-many relationship. |
236 | // |
237 | // each reKind is associated with one or more hresults. |
238 | // every hresult is associated with exactly one reKind (with kCOMException being the catch-all.) |
239 | static RuntimeExceptionKind GetKindFromHR(HRESULT hr, bool fIsWinRtMode = false); |
240 | protected: |
241 | static HRESULT GetHRFromKind(RuntimeExceptionKind reKind); |
242 | |
243 | #ifdef _DEBUG |
244 | EEException() : m_kind(kException) |
245 | { |
246 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
247 | // We need a variant which does not allocate memory. |
248 | } |
249 | #endif // _DEBUG |
250 | |
251 | virtual Exception *CloneHelper() |
252 | { |
253 | WRAPPER_NO_CONTRACT; |
254 | return new EEException(m_kind); |
255 | } |
256 | |
257 | }; |
258 | |
259 | // --------------------------------------------------------------------------- |
260 | // EEMessageException is an EE exception subclass composed of a type and |
261 | // an unmanaged message of some sort. |
262 | // --------------------------------------------------------------------------- |
263 | |
264 | class EEMessageException : public EEException |
265 | { |
266 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
267 | |
268 | private: |
269 | HRESULT m_hr; |
270 | UINT m_resID; |
271 | InlineSString<32> m_arg1; |
272 | InlineSString<32> m_arg2; |
273 | SString m_arg3; |
274 | SString m_arg4; |
275 | SString m_arg5; |
276 | SString m_arg6; |
277 | |
278 | public: |
279 | EEMessageException(RuntimeExceptionKind kind, UINT resID = 0, LPCWSTR szArg1 = NULL, LPCWSTR szArg2 = NULL, |
280 | LPCWSTR szArg3 = NULL, LPCWSTR szArg4 = NULL, LPCWSTR szArg5 = NULL, LPCWSTR szArg6 = NULL); |
281 | |
282 | EEMessageException(HRESULT hr); |
283 | |
284 | EEMessageException(HRESULT hr, bool fUseCOMException); |
285 | |
286 | EEMessageException(HRESULT hr, UINT resID, LPCWSTR szArg1 = NULL, LPCWSTR szArg2 = NULL, LPCWSTR szArg3 = NULL, |
287 | LPCWSTR szArg4 = NULL, LPCWSTR szArg5 = NULL, LPCWSTR szArg6 = NULL); |
288 | |
289 | EEMessageException(RuntimeExceptionKind kind, HRESULT hr, UINT resID, LPCWSTR szArg1 = NULL, LPCWSTR szArg2 = NULL, |
290 | LPCWSTR szArg3 = NULL, LPCWSTR szArg4 = NULL, LPCWSTR szArg5 = NULL, LPCWSTR szArg6 = NULL); |
291 | |
292 | // Virtual overrides |
293 | HRESULT GetHR(); |
294 | |
295 | BOOL GetThrowableMessage(SString &result); |
296 | |
297 | UINT GetResID(void) { LIMITED_METHOD_CONTRACT; return m_resID; } |
298 | |
299 | static BOOL IsEEMessageException(Exception *pException) |
300 | { |
301 | return (*(PVOID*)pException == GetEEMessageExceptionVPtr()); |
302 | } |
303 | |
304 | protected: |
305 | |
306 | virtual Exception *CloneHelper() |
307 | { |
308 | WRAPPER_NO_CONTRACT; |
309 | return new EEMessageException( |
310 | m_kind, m_hr, m_resID, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6); |
311 | } |
312 | |
313 | |
314 | private: |
315 | |
316 | static PVOID GetEEMessageExceptionVPtr() |
317 | { |
318 | CONTRACT (PVOID) |
319 | { |
320 | WRAPPER(THROWS); |
321 | WRAPPER(GC_TRIGGERS); |
322 | MODE_ANY; |
323 | POSTCONDITION(CheckPointer(RETVAL)); |
324 | } |
325 | CONTRACT_END; |
326 | |
327 | EEMessageException boilerplate(E_FAIL); |
328 | RETURN (PVOID&)boilerplate; |
329 | } |
330 | |
331 | BOOL GetResourceMessage(UINT iResourceID, SString &result); |
332 | |
333 | #ifdef _DEBUG |
334 | EEMessageException() |
335 | { |
336 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
337 | // We need a variant which does not allocate memory. |
338 | } |
339 | #endif // _DEBUG |
340 | }; |
341 | |
342 | // --------------------------------------------------------------------------- |
343 | // EEResourceException is an EE exception subclass composed of a type and |
344 | // an message using a managed exception resource. |
345 | // --------------------------------------------------------------------------- |
346 | |
347 | class EEResourceException : public EEException |
348 | { |
349 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
350 | |
351 | private: |
352 | InlineSString<32> m_resourceName; |
353 | |
354 | public: |
355 | EEResourceException(RuntimeExceptionKind kind, const SString &resourceName); |
356 | |
357 | // Unmanaged message text containing only the resource name (GC safe) |
358 | void GetMessage(SString &result); |
359 | |
360 | // Throwable message containig the resource contents (not GC safe) |
361 | BOOL GetThrowableMessage(SString &result); |
362 | |
363 | protected: |
364 | |
365 | virtual Exception *CloneHelper() |
366 | { |
367 | WRAPPER_NO_CONTRACT; |
368 | return new EEResourceException(m_kind, m_resourceName); |
369 | } |
370 | |
371 | private: |
372 | #ifdef _DEBUG |
373 | EEResourceException() |
374 | { |
375 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
376 | // We need a variant which does not allocate memory. |
377 | } |
378 | #endif // _DEBUG |
379 | }; |
380 | |
381 | // --------------------------------------------------------------------------- |
382 | // EECOMException is an EE exception subclass composed of COM-generated data. |
383 | // Note that you must ensure that the COM data was not derived from a wrapper |
384 | // on a managed Exception object. (If so, you must compose the exception from |
385 | // the managed object itself.) |
386 | // --------------------------------------------------------------------------- |
387 | |
388 | struct ExceptionData |
389 | { |
390 | HRESULT hr; |
391 | BSTR bstrDescription; |
392 | BSTR bstrSource; |
393 | BSTR bstrHelpFile; |
394 | DWORD dwHelpContext; |
395 | GUID guid; |
396 | #ifdef FEATURE_COMINTEROP |
397 | BSTR bstrRestrictedError; // Returned from IRestrictedErrorInfo::GetErrorDetails |
398 | BSTR bstrReference; // Returned from IRestrictedErrorInfo::GetReference |
399 | BSTR bstrCapabilitySid; // Returned from IRestrictedErrorInfo::GetErrorDetails |
400 | IUnknown *pRestrictedErrorInfo; // AddRef-ed RestrictedErrorInfo pointer |
401 | // We need to keep this alive as long as user need the reference |
402 | BOOL bHasLanguageRestrictedErrorInfo; |
403 | #endif // FEATURE_COMINTEROP |
404 | }; |
405 | |
406 | class EECOMException : public EEException |
407 | { |
408 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
409 | |
410 | private: |
411 | ExceptionData m_ED; |
412 | |
413 | public: |
414 | |
415 | EECOMException(EXCEPINFO *pExcepInfo); |
416 | EECOMException(ExceptionData *pED); |
417 | EECOMException( |
418 | HRESULT hr, |
419 | IErrorInfo *pErrInfo, |
420 | bool fUseCOMException, |
421 | IRestrictedErrorInfo *pRestrictedErrInfo, |
422 | BOOL bHasLanguageRestrictedErrorInfo |
423 | COMMA_INDEBUG(BOOL bCheckInProcCCWTearOff = TRUE)); |
424 | ~EECOMException(); |
425 | |
426 | // Virtual overrides |
427 | HRESULT GetHR(); |
428 | |
429 | BOOL GetThrowableMessage(SString &result); |
430 | OBJECTREF CreateThrowable(); |
431 | |
432 | protected: |
433 | |
434 | virtual Exception *CloneHelper() |
435 | { |
436 | WRAPPER_NO_CONTRACT; |
437 | return new EECOMException(&m_ED); |
438 | } |
439 | |
440 | private: |
441 | #ifdef _DEBUG |
442 | EECOMException() |
443 | { |
444 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
445 | // We need a variant which does not allocate memory. |
446 | ZeroMemory(&m_ED, sizeof(m_ED)); |
447 | } |
448 | #endif // _DEBUG |
449 | }; |
450 | |
451 | // --------------------------------------------------------------------------- |
452 | // EEFieldException is an EE exception subclass composed of a field |
453 | // --------------------------------------------------------------------------- |
454 | class EEFieldException : public EEException |
455 | { |
456 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
457 | |
458 | private: |
459 | FieldDesc *m_pFD; |
460 | MethodDesc *m_pAccessingMD; |
461 | SString m_additionalContext; |
462 | UINT m_messageID; |
463 | |
464 | public: |
465 | EEFieldException(FieldDesc *pField); |
466 | EEFieldException(FieldDesc *pField, MethodDesc *pAccessingMD, const SString &additionalContext, UINT messageID); |
467 | |
468 | BOOL GetThrowableMessage(SString &result); |
469 | virtual BOOL IsDomainBound() {return TRUE;}; |
470 | protected: |
471 | |
472 | virtual Exception *CloneHelper() |
473 | { |
474 | WRAPPER_NO_CONTRACT; |
475 | return new EEFieldException(m_pFD, m_pAccessingMD, m_additionalContext, m_messageID); |
476 | } |
477 | |
478 | private: |
479 | #ifdef _DEBUG |
480 | EEFieldException() |
481 | { |
482 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
483 | // We need a variant which does not allocate memory. |
484 | } |
485 | #endif // _DEBUG |
486 | }; |
487 | |
488 | // --------------------------------------------------------------------------- |
489 | // EEMethodException is an EE exception subclass composed of a field |
490 | // --------------------------------------------------------------------------- |
491 | |
492 | class EEMethodException : public EEException |
493 | { |
494 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
495 | |
496 | private: |
497 | MethodDesc *m_pMD; |
498 | MethodDesc *m_pAccessingMD; |
499 | SString m_additionalContext; |
500 | UINT m_messageID; |
501 | |
502 | public: |
503 | EEMethodException(MethodDesc *pMethod); |
504 | EEMethodException(MethodDesc *pMethod, MethodDesc *pAccessingMD, const SString &additionalContext, UINT messageID); |
505 | |
506 | BOOL GetThrowableMessage(SString &result); |
507 | virtual BOOL IsDomainBound() {return TRUE;}; |
508 | protected: |
509 | |
510 | virtual Exception *CloneHelper() |
511 | { |
512 | WRAPPER_NO_CONTRACT; |
513 | return new EEMethodException(m_pMD, m_pAccessingMD, m_additionalContext, m_messageID); |
514 | } |
515 | |
516 | private: |
517 | #ifdef _DEBUG |
518 | EEMethodException() |
519 | { |
520 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
521 | // We need a variant which does not allocate memory. |
522 | } |
523 | #endif // _DEBUG |
524 | }; |
525 | |
526 | // --------------------------------------------------------------------------- |
527 | // EETypeAccessException is an EE exception subclass composed of a type being |
528 | // illegally accessed and the method doing the access |
529 | // --------------------------------------------------------------------------- |
530 | |
531 | class EETypeAccessException : public EEException |
532 | { |
533 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
534 | |
535 | private: |
536 | MethodTable *m_pMT; |
537 | MethodDesc *m_pAccessingMD; |
538 | SString m_additionalContext; |
539 | UINT m_messageID; |
540 | |
541 | public: |
542 | EETypeAccessException(MethodTable *pMT); |
543 | EETypeAccessException(MethodTable *pMT, MethodDesc *pAccessingMD, const SString &additionalContext, UINT messageID); |
544 | |
545 | BOOL GetThrowableMessage(SString &result); |
546 | virtual BOOL IsDomainBound() {return TRUE;}; |
547 | protected: |
548 | |
549 | virtual Exception *CloneHelper() |
550 | { |
551 | WRAPPER_NO_CONTRACT; |
552 | return new EETypeAccessException(m_pMT, m_pAccessingMD, m_additionalContext, m_messageID); |
553 | } |
554 | |
555 | private: |
556 | #ifdef _DEBUG |
557 | EETypeAccessException() |
558 | { |
559 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
560 | // We need a variant which does not allocate memory. |
561 | } |
562 | #endif // _DEBUG |
563 | }; |
564 | |
565 | // --------------------------------------------------------------------------- |
566 | // EEArgumentException is an EE exception subclass representing a bad argument |
567 | // exception |
568 | // --------------------------------------------------------------------------- |
569 | |
570 | class EEArgumentException : public EEException |
571 | { |
572 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
573 | |
574 | private: |
575 | InlineSString<32> m_argumentName; |
576 | InlineSString<32> m_resourceName; |
577 | |
578 | public: |
579 | EEArgumentException(RuntimeExceptionKind reKind, LPCWSTR pArgName, |
580 | LPCWSTR wszResourceName); |
581 | |
582 | // @todo: GetMessage |
583 | |
584 | OBJECTREF CreateThrowable(); |
585 | |
586 | protected: |
587 | |
588 | virtual Exception *CloneHelper() |
589 | { |
590 | WRAPPER_NO_CONTRACT; |
591 | return new EEArgumentException(m_kind, m_argumentName, m_resourceName); |
592 | } |
593 | |
594 | private: |
595 | #ifdef _DEBUG |
596 | EEArgumentException() |
597 | { |
598 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
599 | // We need a variant which does not allocate memory. |
600 | } |
601 | #endif // _DEBUG |
602 | }; |
603 | |
604 | // --------------------------------------------------------------------------- |
605 | // EETypeLoadException is an EE exception subclass representing a type loading |
606 | // error |
607 | // --------------------------------------------------------------------------- |
608 | |
609 | class EETypeLoadException : public EEException |
610 | { |
611 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
612 | |
613 | private: |
614 | InlineSString<64> m_fullName; |
615 | SString m_pAssemblyName; |
616 | SString m_pMessageArg; |
617 | UINT m_resIDWhy; |
618 | |
619 | public: |
620 | EETypeLoadException(LPCUTF8 pszNameSpace, LPCUTF8 pTypeName, |
621 | LPCWSTR pAssemblyName, LPCUTF8 pMessageArg, UINT resIDWhy); |
622 | |
623 | EETypeLoadException(LPCWSTR pFullTypeName, |
624 | LPCWSTR pAssemblyName, LPCUTF8 pMessageArg, UINT resIDWhy); |
625 | |
626 | // virtual overrides |
627 | void GetMessage(SString &result); |
628 | OBJECTREF CreateThrowable(); |
629 | |
630 | protected: |
631 | |
632 | virtual Exception *CloneHelper() |
633 | { |
634 | WRAPPER_NO_CONTRACT; |
635 | return new EETypeLoadException(m_fullName, m_pAssemblyName, m_pMessageArg, m_resIDWhy); |
636 | } |
637 | |
638 | private: |
639 | EETypeLoadException(const InlineSString<64> &fullName, LPCWSTR pAssemblyName, |
640 | const SString &pMessageArg, UINT resIDWhy) |
641 | : EEException(kTypeLoadException), |
642 | m_fullName(fullName), |
643 | m_pAssemblyName(pAssemblyName), |
644 | m_pMessageArg(pMessageArg), |
645 | m_resIDWhy(resIDWhy) |
646 | { |
647 | WRAPPER_NO_CONTRACT; |
648 | } |
649 | |
650 | |
651 | #ifdef _DEBUG |
652 | EETypeLoadException() |
653 | { |
654 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
655 | // We need a variant which does not allocate memory. |
656 | } |
657 | #endif // _DEBUG |
658 | }; |
659 | |
660 | // --------------------------------------------------------------------------- |
661 | // EEFileLoadException is an EE exception subclass representing a file loading |
662 | // error |
663 | // --------------------------------------------------------------------------- |
664 | |
665 | class EEFileLoadException : public EEException |
666 | { |
667 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
668 | |
669 | private: |
670 | SString m_name; |
671 | void *m_pFusionLog; |
672 | HRESULT m_hr; |
673 | |
674 | |
675 | public: |
676 | |
677 | EEFileLoadException(const SString &name, HRESULT hr, void *pFusionLog = NULL, Exception *pInnerException = NULL); |
678 | ~EEFileLoadException(); |
679 | |
680 | // virtual overrides |
681 | HRESULT GetHR() |
682 | { |
683 | LIMITED_METHOD_DAC_CONTRACT; |
684 | return m_hr; |
685 | } |
686 | void GetMessage(SString &result); |
687 | void GetName(SString &result); |
688 | OBJECTREF CreateThrowable(); |
689 | |
690 | static RuntimeExceptionKind GetFileLoadKind(HRESULT hr); |
691 | static void DECLSPEC_NORETURN Throw(AssemblySpec *pSpec, HRESULT hr, Exception *pInnerException = NULL); |
692 | static void DECLSPEC_NORETURN Throw(PEFile *pFile, HRESULT hr, Exception *pInnerException = NULL); |
693 | static void DECLSPEC_NORETURN Throw(LPCWSTR path, HRESULT hr, Exception *pInnerException = NULL); |
694 | static void DECLSPEC_NORETURN Throw(PEAssembly *parent, const void *memory, COUNT_T size, HRESULT hr, Exception *pInnerException = NULL); |
695 | static BOOL CheckType(Exception* ex); // typeof(EEFileLoadException) |
696 | |
697 | protected: |
698 | virtual Exception *CloneHelper() |
699 | { |
700 | WRAPPER_NO_CONTRACT; |
701 | return new EEFileLoadException(m_name, m_hr, m_pFusionLog); |
702 | } |
703 | |
704 | private: |
705 | #ifdef _DEBUG |
706 | EEFileLoadException() : m_pFusionLog(NULL) |
707 | { |
708 | // Used only for DebugIsEECxxExceptionPointer to get the vtable pointer. |
709 | // We need a variant which does not allocate memory. |
710 | } |
711 | #endif // _DEBUG |
712 | |
713 | void SetFileName(const SString &fileName, BOOL removePath); |
714 | }; |
715 | |
716 | // ------------------------------------------------------------------------------------------------------- |
717 | // Throw/catch macros. These are derived from the generic EXCEPTION macros, |
718 | // but add extra functionality for cleaning up thread state on catches |
719 | // |
720 | // Usage: |
721 | // EX_TRY |
722 | // { |
723 | // EX_THROW(EEMessageException, (kind, L"Failure message")); |
724 | // } |
725 | // EX_CATCH |
726 | // { |
727 | // EX_RETHROW() |
728 | // } |
729 | // EX_END_CATCH(RethrowTerminalExceptions or RethrowCorruptingExceptions) |
730 | // -------------------------------------------------------------------------------------------------------- |
731 | |
732 | // In DAC builds, we don't want to override the normal utilcode exception handling. |
733 | // We're not actually running in the CLR, but we may need access to some CLR-exception |
734 | // related data structures elsewhere in this header file in order to analyze CLR |
735 | // exceptions that occurred in the target. |
736 | #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
737 | |
738 | #define GET_THROWABLE() CLRException::GetThrowableFromException(GET_EXCEPTION()) |
739 | |
740 | #ifdef FEATURE_CORRUPTING_EXCEPTIONS |
741 | |
742 | // For the VM folder, we redefine SET_CE_RETHROW_FLAG_FOR_EX_CATCH to also check the |
743 | // corruption severity when deciding whether to rethrow them or not. |
744 | // |
745 | // We also check the global override flag incase it has been set to force pre-V4 behaviour. |
746 | // |
747 | // Doing the checks for "__fCaughtSO" and "__fCaughtNonCxx" will ensure that we check for |
748 | // corruption severity only if the last exception was a managed exception that could have been rethrown in the VM. |
749 | // When "(__fCaughtSO == FALSE) && (__fCaughtNonCxx == true)" is true, it implies we are dealing with a managed exception |
750 | // inside the VM that is represented by the CLRLastThrownObjectException instance (see EX_TRY/EX_CATCH implementation in VM |
751 | // folder to see how CLRLastThrownObjectException is used). |
752 | // |
753 | // This macro also supports the following scenarios: |
754 | // |
755 | // Scenario 1 |
756 | // ---------- |
757 | // |
758 | // [VM1] -> [VM2] -> <managed code> |
759 | // |
760 | // If a managed exception is swallowed by an EX_CATCH in native function VM2, which then returns back |
761 | // to native function VM1 that throws, for example, a VM C++ exception, an EX_CATCH(RethrowCorruptingExceptions) |
762 | // in VM1 that catches the C++ exception will not rethrow since the last exception was not a managed CSE but |
763 | // a C++ exception. |
764 | // |
765 | // A variation of this is for VM2 to return back in VM1, which calls VM3 that throws a VM C++ exception that |
766 | // reaches VM1's EX_CATCH(RethrowCorruptingExceptions). VM1 shouldn't be rethrowing the exception in such a case. |
767 | // |
768 | // Scenario 2 |
769 | // ---------- |
770 | // |
771 | // [VM1 - RethrowCSE] -> [VM2 - RethrowCSE] -> [VM3 - RethrowCSE] -> <managed code> |
772 | // |
773 | // When managed code throws a CSE (e.g. TargetInvocationException flagged as CSE), [VM3] will rethrow it and we will |
774 | // enter EX_CATCH in VM2 which is supposed to rethrow it as well. But if the implementation of EX_CATCH in VM2 throws |
775 | // another VM C++ exception (e.g. EEFileLoadException) *before* rethrow policy is applied, control will reach EX_CATCH |
776 | // in VM1 that *shouldn't* rethrow (even though it has RethrowCSE as the policy) since the last exception was a VM C++ |
777 | // exception. |
778 | // |
779 | // Scenario 3 |
780 | // ---------- |
781 | // |
782 | // This is about VM throwing a managed exception that gets handled either within the VM, with or without CLR's managed code |
783 | // exception handler coming into the picture. |
784 | // |
785 | // This is explained in detail (alongwith relevant changes) in the implementation of RaiseTheException (in excep.cpp). |
786 | |
787 | #undef SET_CE_RETHROW_FLAG_FOR_EX_CATCH |
788 | #define SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr) ((expr == TRUE) && \ |
789 | (g_pConfig->LegacyCorruptedStateExceptionsPolicy() == false) && \ |
790 | (CEHelper::IsProcessCorruptedStateException(GetCurrentExceptionCode(), FALSE) || \ |
791 | ((!__state.DidCatchSO()) && (!__state.DidCatchCxx()) && \ |
792 | CEHelper::IsLastActiveExceptionCorrupting(TRUE)))) |
793 | |
794 | #endif // FEATURE_CORRUPTING_EXCEPTIONS |
795 | |
796 | #undef EX_TRY |
797 | #define EX_TRY \ |
798 | EX_TRY_CUSTOM(CLRException::HandlerState, (::GetThreadNULLOk()), CLRLastThrownObjectException) |
799 | |
800 | #undef EX_TRY_CPP_ONLY |
801 | #define EX_TRY_CPP_ONLY \ |
802 | EX_TRY_CUSTOM_CPP_ONLY(CLRException::HandlerState, (::GetThreadNULLOk()), CLRLastThrownObjectException) |
803 | |
804 | // Faster version with thread, skipping GetThread call |
805 | #define EX_TRY_THREAD(pThread) \ |
806 | EX_TRY_CUSTOM(CLRException::HandlerState, (pThread, CLRException::HandlerState::ThreadIsNotNull), CLRLastThrownObjectException) |
807 | |
808 | #if defined(_DEBUG) |
809 | // Redefine GET_EXCEPTION to validate CLRLastThrownObjectException as much as possible. |
810 | #undef GET_EXCEPTION |
811 | #define GET_EXCEPTION() (__pException == NULL ? __defaultException.Validate() : __pException.GetValue()) |
812 | #endif // _DEBUG |
813 | |
814 | // When we throw an exception, we need stay in SO-intolerant state and |
815 | // probe for sufficient stack so that we don't SO during the processing. |
816 | #undef HANDLE_SO_TOLERANCE_FOR_THROW |
817 | #define HANDLE_SO_TOLERANCE_FOR_THROW STACK_PROBE_FOR_THROW(GetThread()); |
818 | |
819 | LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv); |
820 | |
821 | // Re-define the macro to add automatic restoration of the guard page to PAL_EXCEPT and PAL_EXCEPT_FILTER and |
822 | // friends. Note: RestoreGuardPage will only do work if the guard page is not present. |
823 | #undef PAL_SEH_RESTORE_GUARD_PAGE |
824 | #define PAL_SEH_RESTORE_GUARD_PAGE \ |
825 | if (__exCode == STATUS_STACK_OVERFLOW) \ |
826 | { \ |
827 | Thread *__pThread = GetThread(); \ |
828 | if (__pThread != NULL) \ |
829 | { \ |
830 | __pThread->RestoreGuardPage(); \ |
831 | } \ |
832 | } |
833 | |
834 | #undef EX_TRY_NOCATCH |
835 | #define EX_TRY_NOCATCH(ParamType, paramDef, paramRef) \ |
836 | PAL_TRY(ParamType, __EXparam, paramRef) \ |
837 | { \ |
838 | CLRException::HandlerState __state(::GetThreadNULLOk()); \ |
839 | PAL_TRY(ParamType, paramDef, __EXparam) \ |
840 | { |
841 | |
842 | #undef EX_END_NOCATCH |
843 | #define EX_END_NOCATCH \ |
844 | ; \ |
845 | } \ |
846 | PAL_FINALLY \ |
847 | { \ |
848 | __state.CleanupTry(); \ |
849 | } \ |
850 | PAL_ENDTRY \ |
851 | } \ |
852 | PAL_EXCEPT_FILTER(CLRNoCatchHandler) \ |
853 | { \ |
854 | } \ |
855 | PAL_ENDTRY |
856 | |
857 | // |
858 | // We need a way to identify an exception in managed code that is rethrown from a new exception in managed code |
859 | // when we get into our managed EH logic. Currently, we do that by checking the GC mode. If a thread has preemptive |
860 | // GC enabled, but the IP of the exception is in mangaed code, then it must be a rethrow from unmanaged code |
861 | // (including CLR code.) Therefore, we toggle the GC mode before the rethrow to indicate that. Note: we don't do |
862 | // this if we've caught one of our internal C++ Exception objects: by definition, those don't come from managed |
863 | // code, and this allows us to continue to use EX_RETHROW in no-trigger regions. |
864 | // |
865 | #undef EX_RETHROW |
866 | #define EX_RETHROW \ |
867 | do \ |
868 | { \ |
869 | /* don't embed file names in retail to save space and avoid IP */ \ |
870 | /* a findstr /n will allow you to locate it in a pinch */ \ |
871 | STRESS_LOG1(LF_EH, LL_INFO100, \ |
872 | "EX_RETHROW " INDEBUG(__FILE__) " line %d\n", __LINE__); \ |
873 | __pException.SuppressRelease(); \ |
874 | if ((!__state.DidCatchCxx()) && (GetThread() != NULL)) \ |
875 | { \ |
876 | if (GetThread()->PreemptiveGCDisabled()) \ |
877 | { \ |
878 | LOG((LF_EH, LL_INFO10, "EX_RETHROW: going preemptive\n")); \ |
879 | GetThread()->EnablePreemptiveGC(); \ |
880 | } \ |
881 | } \ |
882 | PAL_CPP_RETHROW; \ |
883 | } while (0) |
884 | |
885 | // |
886 | // Note: we only restore the guard page if we did _not_ catch a C++ exception, since a SO exception is a SEH |
887 | // exception. |
888 | // |
889 | // We also need to restore the SO tolerance state, including restoring the cookie for the current stack guard. |
890 | // |
891 | // For VM code EX_CATCH calls CLREXception::HandleState::SetupCatch(). |
892 | // When Stack guards are disabled we will tear down the process in |
893 | // CLREXception::HandleState::SetupCatch() if there is a StackOverflow. |
894 | // So we should not reach EX_ENDTRY when there is StackOverflow. |
895 | // This change cannot be done in ex.h as for all other code |
896 | // CLREXception::HandleState::SetupCatch() is not called rather |
897 | // EXception::HandleState::SetupCatch() is called which is a nop. |
898 | // |
899 | #undef EX_ENDTRY |
900 | #define EX_ENDTRY \ |
901 | PAL_CPP_ENDTRY \ |
902 | SO_INFRASTRUCTURE_CODE(if (__state.DidCatch()) { RESTORE_SO_TOLERANCE_STATE; }) \ |
903 | SO_INFRASTRUCTURE_CODE(if (__state.DidCatchSO()) { HANDLE_STACKOVERFLOW_AFTER_CATCH; }) \ |
904 | NO_SO_INFRASTRUCTURE_CODE_ASSERTE(!__state.DidCatchSO()) \ |
905 | |
906 | |
907 | // CLRException::GetErrorInfo below invokes GetComIPFromObjectRef |
908 | // that invokes ObjHeader::GetSyncBlock which has the INJECT_FAULT contract. |
909 | // |
910 | // This EX_CATCH_HRESULT implementation can be used in functions |
911 | // that have FORBID_FAULT contracts. |
912 | // |
913 | // However, failure due to OOM (or any other potential exception) in GetErrorInfo |
914 | // implies that we couldnt get the interface pointer from the objectRef and would be |
915 | // returned NULL. |
916 | // |
917 | // Thus, the scoped use of FAULT_NOT_FATAL macro. |
918 | #undef EX_CATCH_HRESULT |
919 | #define EX_CATCH_HRESULT(_hr) \ |
920 | EX_CATCH \ |
921 | { \ |
922 | (_hr) = GET_EXCEPTION()->GetHR(); \ |
923 | { \ |
924 | FAULT_NOT_FATAL(); \ |
925 | HRESULT hrErrorInfo = GET_EXCEPTION()->SetErrorInfo(); \ |
926 | if (FAILED(hrErrorInfo)) \ |
927 | { \ |
928 | (_hr) = hrErrorInfo; \ |
929 | } \ |
930 | } \ |
931 | _ASSERTE(FAILED(_hr)); \ |
932 | } \ |
933 | EX_END_CATCH(SwallowAllExceptions) |
934 | |
935 | #endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE |
936 | |
937 | // When collecting dumps, we need to ignore errors unless the user cancels. |
938 | #define EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED \ |
939 | EX_CATCH \ |
940 | { \ |
941 | /* Swallow the exception and keep going unless COR_E_OPERATIONCANCELED */ \ |
942 | /* was thrown. Used generating dumps, where rethrow will cancel dump. */ \ |
943 | } \ |
944 | EX_END_CATCH(RethrowCancelExceptions) |
945 | |
946 | // Only use this version to wrap single source lines, or it makes debugging painful. |
947 | #define CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED(sourceCode) \ |
948 | EX_TRY \ |
949 | { \ |
950 | sourceCode \ |
951 | } \ |
952 | EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED |
953 | |
954 | |
955 | //============================================================================== |
956 | // High-level macros for common uses of EX_TRY. Try using these rather |
957 | // than the raw EX_TRY constructs. |
958 | //============================================================================== |
959 | |
960 | //=================================================================================== |
961 | // Macro for defining external entrypoints such as COM interop boundaries. |
962 | // The boundary will catch all exceptions (including terminals) and convert |
963 | // them into HR/IErrorInfo pairs as appropriate. |
964 | // |
965 | // Usage: |
966 | // |
967 | // HRESULT hr; ;; BEGIN will initialize HR |
968 | // BEGIN_EXTERNAL_ENTRYPOINT(&hr) |
969 | // <do managed stuff> ;; this part will execute in cooperative GC mode |
970 | // END_EXTERNAL_ENTRYPOINT |
971 | // return hr; |
972 | // |
973 | // Comments: |
974 | // The BEGIN macro will setup a Thread if necessary. It should only be called |
975 | // in preemptive mode. If you are calling it from cooperative mode, this implies |
976 | // we are executing "external" code in cooperative mode. The Reentrancy MDA |
977 | // complains about this. |
978 | // |
979 | // Only use this macro for actual boundaries between CLR and |
980 | // outside unmanaged code. If you want to connect internal pieces |
981 | // of CLR code, use EX_TRY instead. |
982 | //=================================================================================== |
983 | #ifdef MDA_SUPPORTED |
984 | NOINLINE BOOL HasIllegalReentrancyRare(); |
985 | #define HAS_ILLEGAL_REENTRANCY() (NULL != MDA_GET_ASSISTANT(Reentrancy) && HasIllegalReentrancyRare()) |
986 | #else |
987 | #define HAS_ILLEGAL_REENTRANCY() false |
988 | #endif |
989 | |
990 | #define BEGIN_EXTERNAL_ENTRYPOINT(phresult) \ |
991 | { \ |
992 | HRESULT *__phr = (phresult); \ |
993 | *__phr = S_OK; \ |
994 | _ASSERTE(GetThread() == NULL || \ |
995 | !GetThread()->PreemptiveGCDisabled()); \ |
996 | if (HAS_ILLEGAL_REENTRANCY()) \ |
997 | { \ |
998 | *__phr = COR_E_ILLEGAL_REENTRANCY; \ |
999 | } \ |
1000 | else \ |
1001 | if (!CanRunManagedCode()) \ |
1002 | { \ |
1003 | *__phr = E_PROCESS_SHUTDOWN_REENTRY; \ |
1004 | } \ |
1005 | else \ |
1006 | { \ |
1007 | MAKE_CURRENT_THREAD_AVAILABLE_EX(GetThreadNULLOk()); \ |
1008 | if (CURRENT_THREAD == NULL) \ |
1009 | { \ |
1010 | CURRENT_THREAD = SetupThreadNoThrow(__phr); \ |
1011 | } \ |
1012 | if (CURRENT_THREAD != NULL) \ |
1013 | { \ |
1014 | BEGIN_SO_INTOLERANT_CODE_NOTHROW(CURRENT_THREAD, *__phr = COR_E_STACKOVERFLOW); \ |
1015 | EX_TRY_THREAD(CURRENT_THREAD); \ |
1016 | { \ |
1017 | |
1018 | #define END_EXTERNAL_ENTRYPOINT \ |
1019 | } \ |
1020 | EX_CATCH_HRESULT(*__phr); \ |
1021 | END_SO_INTOLERANT_CODE; \ |
1022 | } \ |
1023 | } \ |
1024 | } \ |
1025 | |
1026 | // This macro should be used at the entry points (e.g. COM interop boundaries) |
1027 | // where CE's are not expected to get swallowed. |
1028 | #define END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX(fCond) \ |
1029 | } \ |
1030 | EX_CATCH \ |
1031 | { \ |
1032 | *__phr = GET_EXCEPTION()->GetHR(); \ |
1033 | } \ |
1034 | EX_END_CATCH(RethrowCorruptingExceptionsEx(fCond)); \ |
1035 | END_SO_INTOLERANT_CODE; \ |
1036 | } \ |
1037 | } \ |
1038 | } \ |
1039 | |
1040 | // This macro should be used at the entry points (e.g. COM interop boundaries) |
1041 | // where CE's are not expected to get swallowed. |
1042 | #define END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS \ |
1043 | END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX(TRUE) |
1044 | |
1045 | |
1046 | |
1047 | //============================================================================== |
1048 | |
1049 | // --------------------------------------------------------------------------- |
1050 | // Inline implementations. Pay no attention to that man behind the curtain. |
1051 | // --------------------------------------------------------------------------- |
1052 | |
1053 | inline CLRException::CLRException() |
1054 | : m_throwableHandle(NULL) |
1055 | { |
1056 | LIMITED_METHOD_CONTRACT; |
1057 | } |
1058 | |
1059 | inline void CLRException::SetThrowableHandle(OBJECTHANDLE throwable) |
1060 | { |
1061 | STRESS_LOG1(LF_EH, LL_INFO100, "in CLRException::SetThrowableHandle: obj = %x\n" , throwable); |
1062 | m_throwableHandle = throwable; |
1063 | } |
1064 | |
1065 | inline EEException::EEException(RuntimeExceptionKind kind) |
1066 | : m_kind(kind) |
1067 | { |
1068 | LIMITED_METHOD_CONTRACT; |
1069 | } |
1070 | |
1071 | inline EEException::EEException(HRESULT hr) |
1072 | : m_kind(GetKindFromHR(hr)) |
1073 | { |
1074 | LIMITED_METHOD_CONTRACT; |
1075 | } |
1076 | |
1077 | inline EEMessageException::EEMessageException(HRESULT hr) |
1078 | : EEException(GetKindFromHR(hr)), |
1079 | m_hr(hr), |
1080 | m_resID(0) |
1081 | { |
1082 | WRAPPER_NO_CONTRACT; |
1083 | |
1084 | m_arg1.Printf("%.8x" , hr); |
1085 | } |
1086 | |
1087 | inline EEMessageException::EEMessageException(HRESULT hr, bool fUseCOMException) |
1088 | : EEException(GetKindFromHR(hr, !fUseCOMException)), |
1089 | m_hr(hr), |
1090 | m_resID(0) |
1091 | { |
1092 | WRAPPER_NO_CONTRACT; |
1093 | |
1094 | m_arg1.Printf("%.8x" , hr); |
1095 | } |
1096 | |
1097 | //----------------------------------------------------------------------------- |
1098 | // Constructor with lots of defaults (to 0 / null) |
1099 | // kind -- "clr kind" of the exception |
1100 | // resid -- resource id for message |
1101 | // strings -- substitution text for message |
1102 | inline EEMessageException::EEMessageException(RuntimeExceptionKind kind, UINT resID, LPCWSTR szArg1, LPCWSTR szArg2, |
1103 | LPCWSTR szArg3, LPCWSTR szArg4, LPCWSTR szArg5, LPCWSTR szArg6) |
1104 | : EEException(kind), |
1105 | m_hr(EEException::GetHRFromKind(kind)), |
1106 | m_resID(resID), |
1107 | m_arg1(szArg1), |
1108 | m_arg2(szArg2), |
1109 | m_arg3(szArg3), |
1110 | m_arg4(szArg4), |
1111 | m_arg5(szArg5), |
1112 | m_arg6(szArg6) |
1113 | { |
1114 | WRAPPER_NO_CONTRACT; |
1115 | } |
1116 | |
1117 | //----------------------------------------------------------------------------- |
1118 | // Constructor with lots of defaults (to 0 / null) |
1119 | // hr -- hresult that lead to this exception |
1120 | // resid -- resource id for message |
1121 | // strings -- substitution text for message |
1122 | inline EEMessageException::EEMessageException(HRESULT hr, UINT resID, LPCWSTR szArg1, LPCWSTR szArg2, LPCWSTR szArg3, |
1123 | LPCWSTR szArg4, LPCWSTR szArg5, LPCWSTR szArg6) |
1124 | : EEException(GetKindFromHR(hr)), |
1125 | m_hr(hr), |
1126 | m_resID(resID), |
1127 | m_arg1(szArg1), |
1128 | m_arg2(szArg2), |
1129 | m_arg3(szArg3), |
1130 | m_arg4(szArg4), |
1131 | m_arg5(szArg5), |
1132 | m_arg6(szArg6) |
1133 | { |
1134 | } |
1135 | |
1136 | //----------------------------------------------------------------------------- |
1137 | // Constructor with no defaults |
1138 | // kind -- "clr kind" of the exception |
1139 | // hr -- hresult that lead to this exception |
1140 | // resid -- resource id for message |
1141 | // strings -- substitution text for message |
1142 | inline EEMessageException::EEMessageException(RuntimeExceptionKind kind, HRESULT hr, UINT resID, LPCWSTR szArg1, |
1143 | LPCWSTR szArg2, LPCWSTR szArg3, LPCWSTR szArg4, LPCWSTR szArg5, |
1144 | LPCWSTR szArg6) |
1145 | : EEException(kind), |
1146 | m_hr(hr), |
1147 | m_resID(resID), |
1148 | m_arg1(szArg1), |
1149 | m_arg2(szArg2), |
1150 | m_arg3(szArg3), |
1151 | m_arg4(szArg4), |
1152 | m_arg5(szArg5), |
1153 | m_arg6(szArg6) |
1154 | { |
1155 | WRAPPER_NO_CONTRACT; |
1156 | } |
1157 | |
1158 | |
1159 | inline EEResourceException::EEResourceException(RuntimeExceptionKind kind, const SString &resourceName) |
1160 | : EEException(kind), |
1161 | m_resourceName(resourceName) |
1162 | { |
1163 | WRAPPER_NO_CONTRACT; |
1164 | } |
1165 | |
1166 | |
1167 | inline EEFieldException::EEFieldException(FieldDesc *pField) |
1168 | : EEException(kFieldAccessException), |
1169 | m_pFD(pField), |
1170 | m_pAccessingMD(NULL), |
1171 | m_messageID(0) |
1172 | { |
1173 | WRAPPER_NO_CONTRACT; |
1174 | } |
1175 | |
1176 | inline EEFieldException::EEFieldException(FieldDesc *pField, MethodDesc *pAccessingMD, const SString &additionalContext, UINT messageID) |
1177 | : EEException(kFieldAccessException), |
1178 | m_pFD(pField), |
1179 | m_pAccessingMD(pAccessingMD), |
1180 | m_additionalContext(additionalContext), |
1181 | m_messageID(messageID) |
1182 | { |
1183 | } |
1184 | |
1185 | inline EEMethodException::EEMethodException(MethodDesc *pMethod) |
1186 | : EEException(kMethodAccessException), |
1187 | m_pMD(pMethod), |
1188 | m_pAccessingMD(NULL), |
1189 | m_messageID(0) |
1190 | { |
1191 | WRAPPER_NO_CONTRACT; |
1192 | } |
1193 | |
1194 | inline EEMethodException::EEMethodException(MethodDesc *pMethod, MethodDesc *pAccessingMD, const SString &additionalContext, UINT messageID) |
1195 | : EEException(kMethodAccessException), |
1196 | m_pMD(pMethod), |
1197 | m_pAccessingMD(pAccessingMD), |
1198 | m_additionalContext(additionalContext), |
1199 | m_messageID(messageID) |
1200 | { |
1201 | } |
1202 | |
1203 | inline EETypeAccessException::EETypeAccessException(MethodTable *pMT) |
1204 | : EEException(kTypeAccessException), |
1205 | m_pMT(pMT), |
1206 | m_pAccessingMD(NULL), |
1207 | m_messageID(0) |
1208 | { |
1209 | } |
1210 | |
1211 | inline EETypeAccessException::EETypeAccessException(MethodTable *pMT, MethodDesc *pAccessingMD, const SString &additionalContext, UINT messageID) |
1212 | : EEException(kTypeAccessException), |
1213 | m_pMT(pMT), |
1214 | m_pAccessingMD(pAccessingMD), |
1215 | m_additionalContext(additionalContext), |
1216 | m_messageID(messageID) |
1217 | { |
1218 | } |
1219 | |
1220 | inline EEArgumentException::EEArgumentException(RuntimeExceptionKind reKind, LPCWSTR pArgName, |
1221 | LPCWSTR wszResourceName) |
1222 | : EEException(reKind), |
1223 | m_argumentName(pArgName), |
1224 | m_resourceName(wszResourceName) |
1225 | { |
1226 | WRAPPER_NO_CONTRACT; |
1227 | } |
1228 | |
1229 | |
1230 | class ObjrefException : public CLRException |
1231 | { |
1232 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
1233 | |
1234 | public: |
1235 | |
1236 | ObjrefException(); |
1237 | ObjrefException(OBJECTREF throwable); |
1238 | |
1239 | private: |
1240 | static const int c_type = 0x4F522020; // 'OR ' |
1241 | |
1242 | public: |
1243 | // Dynamic type query for catchers |
1244 | static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; } |
1245 | virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; } |
1246 | BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || CLRException::IsType(type); } |
1247 | |
1248 | protected: |
1249 | virtual Exception *CloneHelper() |
1250 | { |
1251 | WRAPPER_NO_CONTRACT; |
1252 | return new ObjrefException(); |
1253 | } |
1254 | |
1255 | virtual Exception *DomainBoundCloneHelper(); |
1256 | }; |
1257 | |
1258 | |
1259 | class CLRLastThrownObjectException : public CLRException |
1260 | { |
1261 | friend bool DebugIsEECxxExceptionPointer(void* pv); |
1262 | |
1263 | public: |
1264 | CLRLastThrownObjectException(); |
1265 | |
1266 | private: |
1267 | static const int c_type = 0x4C544F20; // 'LTO ' |
1268 | |
1269 | public: |
1270 | // Dynamic type query for catchers |
1271 | static int GetType() {LIMITED_METHOD_CONTRACT; return c_type; } |
1272 | virtual int GetInstanceType() { LIMITED_METHOD_CONTRACT; return c_type; } |
1273 | BOOL IsType(int type) { WRAPPER_NO_CONTRACT; return type == c_type || CLRException::IsType(type); } |
1274 | |
1275 | #if defined(_DEBUG) |
1276 | CLRLastThrownObjectException* Validate(); |
1277 | #endif // _DEBUG |
1278 | |
1279 | protected: |
1280 | virtual Exception *CloneHelper(); |
1281 | |
1282 | virtual Exception *DomainBoundCloneHelper(); |
1283 | |
1284 | virtual OBJECTREF CreateThrowable(); |
1285 | }; |
1286 | |
1287 | // Returns true if the HRESULT maps to the RuntimeExceptionKind (hr => kind). |
1288 | bool IsHRESULTForExceptionKind(HRESULT hr, RuntimeExceptionKind kind); |
1289 | |
1290 | #endif // _CLREX_H_ |
1291 | |
1292 | |