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 | #ifndef CHECK_INL_ |
6 | #define CHECK_INL_ |
7 | |
8 | #include "check.h" |
9 | #include "clrhost.h" |
10 | #include "debugmacros.h" |
11 | #include "clrtypes.h" |
12 | |
13 | inline LONG *CHECK::InitTls() |
14 | { |
15 | #pragma push_macro("HeapAlloc") |
16 | #pragma push_macro("GetProcessHeap") |
17 | #undef HeapAlloc |
18 | #undef GetProcessHeap |
19 | |
20 | LONG *pCount = (LONG *)::HeapAlloc(GetProcessHeap(), 0, sizeof(LONG)); |
21 | if (pCount) |
22 | *pCount = 0; |
23 | |
24 | #pragma pop_macro("HeapAlloc") |
25 | #pragma pop_macro("GetProcessHeap") |
26 | ClrFlsSetValue(TlsIdx_Check, pCount); |
27 | ClrFlsAssociateCallback(TlsIdx_Check, ReleaseCheckTls); |
28 | return pCount; |
29 | } |
30 | |
31 | inline void CHECK::ReleaseTls(void* pCountTLS) |
32 | { |
33 | #pragma push_macro("HeapFree") |
34 | #pragma push_macro("GetProcessHeap") |
35 | #undef HeapFree |
36 | #undef GetProcessHeap |
37 | LONG* pCount = (LONG*) pCountTLS; |
38 | if (pCount) |
39 | ::HeapFree(GetProcessHeap(), 0, pCount); |
40 | |
41 | #pragma pop_macro("HeapFree") |
42 | #pragma pop_macro("GetProcessHeap") |
43 | } |
44 | |
45 | FORCEINLINE BOOL CHECK::EnterAssert() |
46 | { |
47 | if (s_neverEnforceAsserts) |
48 | return FALSE; |
49 | |
50 | #ifdef _DEBUG_IMPL |
51 | m_pCount = (LONG *)ClrFlsGetValue(TlsIdx_Check); |
52 | if (!m_pCount) |
53 | { |
54 | m_pCount = InitTls(); |
55 | if (!m_pCount) |
56 | return FALSE; |
57 | } |
58 | |
59 | if (!*m_pCount) |
60 | { |
61 | *m_pCount = 1; |
62 | return TRUE; |
63 | } |
64 | else |
65 | return FALSE; |
66 | #else |
67 | // Don't bother doing recursive checks on a free build, since checks should |
68 | // be extremely isolated |
69 | return TRUE; |
70 | #endif |
71 | } |
72 | |
73 | FORCEINLINE void CHECK::LeaveAssert() |
74 | { |
75 | #ifdef _DEBUG_IMPL |
76 | *m_pCount = 0; |
77 | #endif |
78 | } |
79 | |
80 | FORCEINLINE BOOL CHECK::IsInAssert() |
81 | { |
82 | #ifdef _DEBUG_IMPL |
83 | if (!m_pCount) |
84 | m_pCount = (LONG *)ClrFlsGetValue(TlsIdx_Check); |
85 | |
86 | if (!m_pCount) |
87 | return FALSE; |
88 | else |
89 | return *m_pCount; |
90 | #else |
91 | return FALSE; |
92 | #endif |
93 | } |
94 | |
95 | FORCEINLINE BOOL CHECK::EnforceAssert() |
96 | { |
97 | if (s_neverEnforceAsserts) |
98 | return FALSE; |
99 | else |
100 | { |
101 | CHECK chk; |
102 | return !chk.IsInAssert(); |
103 | } |
104 | } |
105 | |
106 | FORCEINLINE void CHECK::ResetAssert() |
107 | { |
108 | CHECK chk; |
109 | if (chk.IsInAssert()) |
110 | chk.LeaveAssert(); |
111 | } |
112 | |
113 | inline void CHECK::SetAssertEnforcement(BOOL value) |
114 | { |
115 | s_neverEnforceAsserts = !value; |
116 | } |
117 | |
118 | // Fail records the result of a condition check. Can take either a |
119 | // boolean value or another check result |
120 | FORCEINLINE BOOL CHECK::Fail(BOOL condition) |
121 | { |
122 | #ifdef _DEBUG |
123 | if (!condition) |
124 | { |
125 | m_condition = NULL; |
126 | m_file = NULL; |
127 | m_line = 0; |
128 | } |
129 | #endif |
130 | return !condition; |
131 | } |
132 | |
133 | FORCEINLINE BOOL CHECK::Fail(const CHECK &check) |
134 | { |
135 | m_message = check.m_message; |
136 | #ifdef _DEBUG |
137 | if (m_message != NULL) |
138 | { |
139 | m_condition = check.m_condition; |
140 | m_file = check.m_file; |
141 | m_line = check.m_line; |
142 | } |
143 | #endif |
144 | return m_message != NULL; |
145 | } |
146 | |
147 | #ifndef _DEBUG |
148 | FORCEINLINE void CHECK::Setup(LPCSTR message) |
149 | { |
150 | m_message = message; |
151 | } |
152 | |
153 | FORCEINLINE LPCSTR CHECK::FormatMessage(LPCSTR messageFormat, ...) |
154 | { |
155 | return messageFormat; |
156 | } |
157 | #endif |
158 | |
159 | FORCEINLINE CHECK::operator BOOL () |
160 | { |
161 | return m_message == NULL; |
162 | } |
163 | |
164 | FORCEINLINE BOOL CHECK::operator!() |
165 | { |
166 | return m_message != NULL; |
167 | } |
168 | |
169 | inline CHECK CheckAlignment(UINT alignment) |
170 | { |
171 | STATIC_CONTRACT_WRAPPER; |
172 | CHECK((alignment & (alignment-1)) == 0); |
173 | CHECK_OK; |
174 | } |
175 | |
176 | inline CHECK CheckAligned(UINT value, UINT alignment) |
177 | { |
178 | STATIC_CONTRACT_WRAPPER; |
179 | CHECK(AlignmentTrim(value, alignment) == 0); |
180 | CHECK_OK; |
181 | } |
182 | |
183 | #ifndef PLATFORM_UNIX |
184 | // For Unix this and the previous function get the same types. |
185 | // So, exclude this one. |
186 | inline CHECK CheckAligned(ULONG value, UINT alignment) |
187 | { |
188 | STATIC_CONTRACT_WRAPPER; |
189 | CHECK(AlignmentTrim(value, alignment) == 0); |
190 | CHECK_OK; |
191 | } |
192 | #endif // PLATFORM_UNIX |
193 | |
194 | inline CHECK CheckAligned(UINT64 value, UINT alignment) |
195 | { |
196 | STATIC_CONTRACT_WRAPPER; |
197 | CHECK(AlignmentTrim(value, alignment) == 0); |
198 | CHECK_OK; |
199 | } |
200 | |
201 | inline CHECK CheckAligned(const void *address, UINT alignment) |
202 | { |
203 | STATIC_CONTRACT_WRAPPER; |
204 | CHECK(AlignmentTrim((SIZE_T)address, alignment) == 0); |
205 | CHECK_OK; |
206 | } |
207 | |
208 | inline CHECK CheckOverflow(UINT value1, UINT value2) |
209 | { |
210 | CHECK(value1 + value2 >= value1); |
211 | CHECK_OK; |
212 | } |
213 | |
214 | #if defined(_MSC_VER) |
215 | inline CHECK CheckOverflow(ULONG value1, ULONG value2) |
216 | { |
217 | CHECK(value1 + value2 >= value1); |
218 | CHECK_OK; |
219 | } |
220 | #endif |
221 | |
222 | inline CHECK CheckOverflow(UINT64 value1, UINT64 value2) |
223 | { |
224 | CHECK(value1 + value2 >= value1); |
225 | CHECK_OK; |
226 | } |
227 | |
228 | inline CHECK CheckOverflow(PTR_CVOID address, UINT offset) |
229 | { |
230 | TADDR targetAddr = dac_cast<TADDR>(address); |
231 | #if POINTER_BITS == 32 |
232 | CHECK((UINT) (SIZE_T)(targetAddr) + offset >= (UINT) (SIZE_T) (targetAddr)); |
233 | #else |
234 | CHECK((UINT64) targetAddr + offset >= (UINT64) targetAddr); |
235 | #endif |
236 | |
237 | CHECK_OK; |
238 | } |
239 | |
240 | #if defined(_MSC_VER) |
241 | inline CHECK CheckOverflow(const void *address, ULONG offset) |
242 | { |
243 | #if POINTER_BITS == 32 |
244 | CHECK((ULONG) (SIZE_T) address + offset >= (ULONG) (SIZE_T) address); |
245 | #else |
246 | CHECK((UINT64) address + offset >= (UINT64) address); |
247 | #endif |
248 | |
249 | CHECK_OK; |
250 | } |
251 | #endif |
252 | |
253 | inline CHECK CheckOverflow(const void *address, UINT64 offset) |
254 | { |
255 | #if POINTER_BITS == 32 |
256 | CHECK(offset >> 32 == 0); |
257 | CHECK((UINT) (SIZE_T) address + (UINT) offset >= (UINT) (SIZE_T) address); |
258 | #else |
259 | CHECK((UINT64) address + offset >= (UINT64) address); |
260 | #endif |
261 | |
262 | CHECK_OK; |
263 | } |
264 | |
265 | |
266 | inline CHECK CheckUnderflow(UINT value1, UINT value2) |
267 | { |
268 | CHECK(value1 - value2 <= value1); |
269 | |
270 | CHECK_OK; |
271 | } |
272 | |
273 | #ifndef PLATFORM_UNIX |
274 | // For Unix this and the previous function get the same types. |
275 | // So, exclude this one. |
276 | inline CHECK CheckUnderflow(ULONG value1, ULONG value2) |
277 | { |
278 | CHECK(value1 - value2 <= value1); |
279 | |
280 | CHECK_OK; |
281 | } |
282 | #endif // PLATFORM_UNIX |
283 | |
284 | inline CHECK CheckUnderflow(UINT64 value1, UINT64 value2) |
285 | { |
286 | CHECK(value1 - value2 <= value1); |
287 | |
288 | CHECK_OK; |
289 | } |
290 | |
291 | inline CHECK CheckUnderflow(const void *address, UINT offset) |
292 | { |
293 | #if POINTER_BITS == 32 |
294 | CHECK((UINT) (SIZE_T) address - offset <= (UINT) (SIZE_T) address); |
295 | #else |
296 | CHECK((UINT64) address - offset <= (UINT64) address); |
297 | #endif |
298 | |
299 | CHECK_OK; |
300 | } |
301 | |
302 | #if defined(_MSC_VER) |
303 | inline CHECK CheckUnderflow(const void *address, ULONG offset) |
304 | { |
305 | #if POINTER_BITS == 32 |
306 | CHECK((ULONG) (SIZE_T) address - offset <= (ULONG) (SIZE_T) address); |
307 | #else |
308 | CHECK((UINT64) address - offset <= (UINT64) address); |
309 | #endif |
310 | |
311 | CHECK_OK; |
312 | } |
313 | #endif |
314 | |
315 | inline CHECK CheckUnderflow(const void *address, UINT64 offset) |
316 | { |
317 | #if POINTER_BITS == 32 |
318 | CHECK(offset >> 32 == 0); |
319 | CHECK((UINT) (SIZE_T) address - (UINT) offset <= (UINT) (SIZE_T) address); |
320 | #else |
321 | CHECK((UINT64) address - offset <= (UINT64) address); |
322 | #endif |
323 | |
324 | CHECK_OK; |
325 | } |
326 | |
327 | inline CHECK CheckUnderflow(const void *address, void *address2) |
328 | { |
329 | #if POINTER_BITS == 32 |
330 | CHECK((UINT) (SIZE_T) address - (UINT) (SIZE_T) address2 <= (UINT) (SIZE_T) address); |
331 | #else |
332 | CHECK((UINT64) address - (UINT64) address2 <= (UINT64) address); |
333 | #endif |
334 | |
335 | CHECK_OK; |
336 | } |
337 | |
338 | inline CHECK CheckZeroedMemory(const void *memory, SIZE_T size) |
339 | { |
340 | CHECK(CheckOverflow(memory, size)); |
341 | |
342 | BYTE *p = (BYTE *) memory; |
343 | BYTE *pEnd = p + size; |
344 | |
345 | while (p < pEnd) |
346 | CHECK(*p++ == 0); |
347 | |
348 | CHECK_OK; |
349 | } |
350 | |
351 | inline CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset) |
352 | { |
353 | CHECK(CheckOverflow(dac_cast<PTR_CVOID>(rangeBase), rangeSize)); |
354 | CHECK(offset <= rangeSize); |
355 | CHECK_OK; |
356 | } |
357 | |
358 | inline CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset, UINT32 size) |
359 | { |
360 | CHECK(CheckOverflow(dac_cast<PTR_CVOID>(rangeBase), rangeSize)); |
361 | CHECK(CheckOverflow(offset, size)); |
362 | CHECK(offset + size <= rangeSize); |
363 | CHECK_OK; |
364 | } |
365 | |
366 | #endif // CHECK_INL_ |
367 | |
368 | |