[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / check.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 //================================================================================
6 // Assertion checking infrastructure
7 //================================================================================
8
9 #include "stdafx.h"
10 #include <check.h>
11 #include <sstring.h>
12 #include <ex.h>
13 #include <contract.h>
14
15 #ifdef _DEBUG
16 size_t CHECK::s_cLeakedBytes = 0;
17 size_t CHECK::s_cNumFailures = 0;
18 #endif
19
20 BOOL CHECK::s_neverEnforceAsserts = 0;
21
22
23 // Currently used for scan SPECIAL_HOLDER_* trickery
24 DEBUG_NOINLINE BOOL CHECK::EnforceAssert_StaticCheckOnly()
25 {
26     return s_neverEnforceAsserts;
27 }
28
29 #ifdef ENABLE_CONTRACTS_IMPL
30 // Need a place to stick this, there is no contract.cpp...
31 BOOL BaseContract::s_alwaysEnforceContracts = 1;
32
33
34 void PAL_TryMarker::Enter()
35 {
36     SCAN_SCOPE_BEGIN;
37     STATIC_CONTRACT_THROWS;
38 };
39
40 void PAL_TryMarker::Leave()
41 {
42     SCAN_SCOPE_END;
43 };
44
45
46 #define SPECIALIZE_CONTRACT_VIOLATION_HOLDER(mask)                              \
47 template<> void ContractViolationHolder<mask>::Enter()                          \
48 {                                                                               \
49     SCAN_SCOPE_BEGIN;                                                           \
50     ANNOTATION_VIOLATION(mask);                                                 \
51     EnterInternal(mask);                                                        \
52 };
53
54 #define SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER(mask)                                                 \
55 template<> AutoCleanupContractViolationHolder<mask>::AutoCleanupContractViolationHolder(BOOL fEnterViolation)   \
56 {                                                                                                               \
57     SCAN_SCOPE_BEGIN;                                                                                           \
58     ANNOTATION_VIOLATION(mask);                                                                                 \
59     EnterInternal(fEnterViolation ? mask : 0);                                                                  \
60 };
61
62 #define SPECIALIZED_VIOLATION(mask)                                             \
63     SPECIALIZE_CONTRACT_VIOLATION_HOLDER(mask);                                 \
64     SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER(mask)
65
66 // There is a special case that requires 0... Why??? Who knows, let's fix that case.
67
68 SPECIALIZED_VIOLATION(0);
69
70 // Basic Specializations
71
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);
81
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.
84
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);
104
105
106
107 #undef SPECIALIZED_VIOLATION
108 #undef SPECIALIZE_AUTO_CLEANUP_CONTRACT_VIOLATION_HOLDER
109 #undef SPECIALIZE_CONTRACT_VIOLATION_HOLDER
110
111 #endif
112
113 // Trigger triggers the actual check failure.  The trigger may provide a reason
114 // to include in the failure message.
115
116 void CHECK::Trigger(LPCSTR reason) 
117 {
118     STATIC_CONTRACT_NOTHROW;
119     STATIC_CONTRACT_GC_NOTRIGGER;
120
121     const char *messageString = NULL;
122     NewHolder<StackScratchBuffer> pScratch(NULL);
123     NewHolder<StackSString> pMessage(NULL);
124
125     EX_TRY
126     {
127         FAULT_NOT_FATAL();
128
129         pScratch = new StackScratchBuffer();
130         pMessage = new StackSString();
131
132         pMessage->AppendASCII(reason);
133         pMessage->AppendASCII(": ");
134         if (m_message != NULL)
135             pMessage->AppendASCII((m_message != (LPCSTR)1) ? m_message : "<runtime check failure>");
136
137 #if _DEBUG
138         pMessage->AppendASCII("FAILED: ");
139         pMessage->AppendASCII(m_condition);
140 #endif
141
142         messageString = pMessage->GetANSI(*pScratch);
143     }
144     EX_CATCH
145     {
146         messageString = "<exception occurred while building failure description>";
147     }
148     EX_END_CATCH(SwallowAllExceptions);
149
150 #if _DEBUG
151     DbgAssertDialog((char*)m_file, m_line, (char *)messageString);
152 #else
153     OutputDebugStringA(messageString);
154     DebugBreak();
155 #endif
156
157 }
158
159 #ifdef _DEBUG
160 // Setup records context info after a failure.
161
162 void CHECK::Setup(LPCSTR message, LPCSTR condition, LPCSTR file, INT line) 
163 {
164     STATIC_CONTRACT_NOTHROW;
165     STATIC_CONTRACT_GC_NOTRIGGER;
166     STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
167
168     // 
169     // It might be nice to collect all of the message here.  But for now, we will just
170     // retain the innermost one.
171     //
172
173     if (m_message == NULL)
174     {
175         m_message = message;
176         m_condition = condition;
177         m_file = file;
178         m_line = line;
179     }
180
181 #ifdef _DEBUG
182     else if (IsInAssert())
183     {
184         EX_TRY
185         {
186             FAULT_NOT_FATAL();
187             // Try to build a stack of condition failures
188
189             StackSString context;
190             context.Printf("%s\n\t%s%s FAILED: %s\n\t\t%s, line: %d",
191                            m_condition, 
192                            message && *message ? message : "", 
193                            message && *message ? ": " : "", 
194                            condition,
195                            file, line);
196
197             m_condition = AllocateDynamicMessage(context);
198         }
199         EX_CATCH
200         {
201             // If anything goes wrong, we don't push extra context
202         }
203         EX_END_CATCH(SwallowAllExceptions)
204     }
205 #endif
206
207 #if defined(_DEBUG_IMPL)
208     if (IsInAssert() && IsDebuggerPresent())
209     {
210         DebugBreak();
211     }
212 #endif
213 }
214
215 LPCSTR CHECK::FormatMessage(LPCSTR messageFormat, ...)
216 {
217     STATIC_CONTRACT_NOTHROW;
218     STATIC_CONTRACT_GC_NOTRIGGER;
219
220     LPCSTR result = NULL;
221
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.
227
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.
232
233     CHECK chk;
234     if (!chk.IsInAssert())
235         result = messageFormat;
236     else
237     {
238         // This path is only run in debug.  TakesLockViolation suppresses
239         // problems with SString below.
240         CONTRACT_VIOLATION(FaultNotFatal|TakesLockViolation);
241
242         EX_TRY
243         {
244             SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
245         
246             // Format it.   
247             va_list args;
248             va_start( args, messageFormat);
249
250             SString s;
251             s.VPrintf(messageFormat, args);
252
253             va_end(args);
254
255             result = AllocateDynamicMessage(s);
256
257         }
258         EX_CATCH
259         {
260             // If anything goes wrong, just use the format string.
261             result = messageFormat;    
262         }
263         EX_END_CATCH(SwallowAllExceptions)
264     }
265
266     return result;
267 }
268
269 LPCSTR CHECK::AllocateDynamicMessage(const SString &s)
270 {
271     STATIC_CONTRACT_NOTHROW;
272     STATIC_CONTRACT_GC_NOTRIGGER;
273
274     // Make a copy of it.
275     StackScratchBuffer buffer;
276     const char * pMsg = s.GetANSI(buffer);
277
278     // Must copy that into our own field.
279     size_t len = strlen(pMsg) + 1;    
280     char * p = new char[len];
281     strcpy(p, pMsg);
282
283     // But we'll keep counters of how much we're leaking for diagnostic purposes.
284     s_cLeakedBytes += len;
285     s_cNumFailures ++;
286
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");
290     return p;
291 }
292
293 void WINAPI ReleaseCheckTls(LPVOID pTlsData)
294 {
295     CHECK::ReleaseTls(pTlsData);    
296 }
297
298 #endif