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