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.
5 //================================================================================
6 // Assertion checking infrastructure
7 //================================================================================
16 size_t CHECK::s_cLeakedBytes = 0;
17 size_t CHECK::s_cNumFailures = 0;
20 BOOL CHECK::s_neverEnforceAsserts = 0;
23 // Currently used for scan SPECIAL_HOLDER_* trickery
24 DEBUG_NOINLINE BOOL CHECK::EnforceAssert_StaticCheckOnly()
26 return s_neverEnforceAsserts;
29 #ifdef ENABLE_CONTRACTS_IMPL
30 // Need a place to stick this, there is no contract.cpp...
31 BOOL BaseContract::s_alwaysEnforceContracts = 1;
34 void PAL_TryMarker::Enter()
37 STATIC_CONTRACT_THROWS;
40 void PAL_TryMarker::Leave()
46 #define SPECIALIZE_CONTRACT_VIOLATION_HOLDER(mask) \
47 template<> void ContractViolationHolder<mask>::Enter() \
50 ANNOTATION_VIOLATION(mask); \
51 EnterInternal(mask); \
54 #define SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER(mask) \
55 template<> AutoCleanupContractViolationHolder<mask>::AutoCleanupContractViolationHolder(BOOL fEnterViolation) \
58 ANNOTATION_VIOLATION(mask); \
59 EnterInternal(fEnterViolation ? mask : 0); \
62 #define SPECIALIZED_VIOLATION(mask) \
63 SPECIALIZE_CONTRACT_VIOLATION_HOLDER(mask); \
64 SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER(mask)
66 // There is a special case that requires 0... Why??? Who knows, let's fix that case.
68 SPECIALIZED_VIOLATION(0);
70 // Basic Specializations
72 SPECIALIZED_VIOLATION(AllViolation);
73 SPECIALIZED_VIOLATION(ThrowsViolation);
74 SPECIALIZED_VIOLATION(GCViolation);
75 SPECIALIZED_VIOLATION(ModeViolation);
76 SPECIALIZED_VIOLATION(FaultViolation);
77 SPECIALIZED_VIOLATION(FaultNotFatal);
78 SPECIALIZED_VIOLATION(HostViolation);
79 SPECIALIZED_VIOLATION(TakesLockViolation);
80 SPECIALIZED_VIOLATION(LoadsTypeViolation);
82 // Other Specializations used by the RUNTIME, if you get a compile time error you need
83 // to add the specific specialization that you are using here.
85 SPECIALIZED_VIOLATION(ThrowsViolation|GCViolation);
86 SPECIALIZED_VIOLATION(ThrowsViolation|GCViolation|TakesLockViolation);
87 SPECIALIZED_VIOLATION(ThrowsViolation|ModeViolation);
88 SPECIALIZED_VIOLATION(ThrowsViolation|FaultNotFatal);
89 SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation);
90 SPECIALIZED_VIOLATION(ThrowsViolation|TakesLockViolation);
91 SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|TakesLockViolation);
92 SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
93 SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|TakesLockViolation|LoadsTypeViolation);
94 SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|ModeViolation);
95 SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|ModeViolation|FaultNotFatal);
96 SPECIALIZED_VIOLATION(ThrowsViolation|FaultViolation|GCViolation|ModeViolation|FaultNotFatal|TakesLockViolation);
97 SPECIALIZED_VIOLATION(GCViolation|FaultViolation);
98 SPECIALIZED_VIOLATION(GCViolation|FaultNotFatal|ModeViolation);
99 SPECIALIZED_VIOLATION(GCViolation|FaultNotFatal|TakesLockViolation);
100 SPECIALIZED_VIOLATION(GCViolation|FaultNotFatal|TakesLockViolation|ModeViolation);
101 SPECIALIZED_VIOLATION(GCViolation|ModeViolation);
102 SPECIALIZED_VIOLATION(FaultViolation|FaultNotFatal);
103 SPECIALIZED_VIOLATION(FaultNotFatal|TakesLockViolation);
107 #undef SPECIALIZED_VIOLATION
108 #undef SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER
109 #undef SPECIALIZE_CONTRACT_VIOLATION_HOLDER
113 // Trigger triggers the actual check failure. The trigger may provide a reason
114 // to include in the failure message.
116 void CHECK::Trigger(LPCSTR reason)
118 STATIC_CONTRACT_NOTHROW;
119 STATIC_CONTRACT_GC_NOTRIGGER;
121 const char *messageString = NULL;
122 NewHolder<StackScratchBuffer> pScratch(NULL);
123 NewHolder<StackSString> pMessage(NULL);
129 pScratch = new StackScratchBuffer();
130 pMessage = new StackSString();
132 pMessage->AppendASCII(reason);
133 pMessage->AppendASCII(": ");
134 if (m_message != NULL)
135 pMessage->AppendASCII((m_message != (LPCSTR)1) ? m_message : "<runtime check failure>");
138 pMessage->AppendASCII("FAILED: ");
139 pMessage->AppendASCII(m_condition);
142 messageString = pMessage->GetANSI(*pScratch);
146 messageString = "<exception occurred while building failure description>";
148 EX_END_CATCH(SwallowAllExceptions);
151 DbgAssertDialog((char*)m_file, m_line, (char *)messageString);
153 OutputDebugStringA(messageString);
160 // Setup records context info after a failure.
162 void CHECK::Setup(LPCSTR message, LPCSTR condition, LPCSTR file, INT line)
164 STATIC_CONTRACT_NOTHROW;
165 STATIC_CONTRACT_GC_NOTRIGGER;
166 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
169 // It might be nice to collect all of the message here. But for now, we will just
170 // retain the innermost one.
173 if (m_message == NULL)
176 m_condition = condition;
182 else if (IsInAssert())
187 // Try to build a stack of condition failures
189 StackSString context;
190 context.Printf("%s\n\t%s%s FAILED: %s\n\t\t%s, line: %d",
192 message && *message ? message : "",
193 message && *message ? ": " : "",
197 m_condition = AllocateDynamicMessage(context);
201 // If anything goes wrong, we don't push extra context
203 EX_END_CATCH(SwallowAllExceptions)
207 #if defined(_DEBUG_IMPL)
208 if (IsInAssert() && IsDebuggerPresent())
215 LPCSTR CHECK::FormatMessage(LPCSTR messageFormat, ...)
217 STATIC_CONTRACT_NOTHROW;
218 STATIC_CONTRACT_GC_NOTRIGGER;
220 LPCSTR result = NULL;
222 // We never delete this allocated string. A dtor would conflict with places
223 // we use this around SEH stuff. We could have some fancy stack-based allocator,
224 // but that's too much work for now. In fact we believe that leaking is a reasonable
225 // policy, since allocations will only happen on a failed assert, and a failed assert
226 // will generally be fatal to the process.
228 // The most common place for format strings will be in an assert; in
229 // which case we don't care about leaking.
230 // But to be safe, if we're not-inside an assert, then we'll just use
231 // the format string literal to avoid allocated (and leaking) any memory.
234 if (!chk.IsInAssert())
235 result = messageFormat;
238 // This path is only run in debug. TakesLockViolation suppresses
239 // problems with SString below.
240 CONTRACT_VIOLATION(FaultNotFatal|TakesLockViolation);
244 SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
248 va_start( args, messageFormat);
251 s.VPrintf(messageFormat, args);
255 result = AllocateDynamicMessage(s);
260 // If anything goes wrong, just use the format string.
261 result = messageFormat;
263 EX_END_CATCH(SwallowAllExceptions)
269 LPCSTR CHECK::AllocateDynamicMessage(const SString &s)
271 STATIC_CONTRACT_NOTHROW;
272 STATIC_CONTRACT_GC_NOTRIGGER;
274 // Make a copy of it.
275 StackScratchBuffer buffer;
276 const char * pMsg = s.GetANSI(buffer);
278 // Must copy that into our own field.
279 size_t len = strlen(pMsg) + 1;
280 char * p = new char[len];
283 // But we'll keep counters of how much we're leaking for diagnostic purposes.
284 s_cLeakedBytes += len;
287 // This should never fire.
288 // Note use an ASSERTE (not a check) to avoid a recursive deadlock.
289 _ASSERTE(s_cLeakedBytes < 10000 || !"Warning - check misuse - leaked over 10,000B due to unexpected usage pattern");
293 void WINAPI ReleaseCheckTls(LPVOID pTlsData)
295 CHECK::ReleaseTls(pTlsData);