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// Check.h
6//
7
8//
9// Assertion checking infrastructure
10// ---------------------------------------------------------------------------
11
12
13#ifndef CHECK_H_
14#define CHECK_H_
15
16#include "static_assert.h"
17#include "daccess.h"
18
19#ifdef _DEBUG
20
21#ifdef _MSC_VER
22// Make sure we can recurse deep enough for FORCEINLINE
23#pragma inline_recursion(on)
24#pragma inline_depth(16)
25#pragma warning(disable:4714)
26#endif // _MSC_VER
27
28#if !defined(DISABLE_CONTRACTS)
29#define CHECK_INVARIANTS 1
30#define VALIDATE_OBJECTS 1
31#endif
32
33#endif // _DEBUG
34
35#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
36#define _DEBUG_IMPL 1
37#endif
38
39#ifdef _DEBUG
40#define DEBUG_ARG(x) , x
41#else
42#define DEBUG_ARG(x)
43#endif
44
45#define CHECK_STRESS 1
46
47//--------------------------------------------------------------------------------
48// A CHECK is an object which encapsulates a potential assertion
49// failure. It not only contains the result of the check, but if the check fails,
50// also records information about the condition and call site.
51//
52// CHECK also serves as a holder to prevent recursive CHECKS. These can be
53// particularly common when putting preconditions inside predicates, especially
54// routines called by an invariant.
55//
56// Note that using CHECK is perfectly efficient in a free build - the CHECK becomes
57// a simple string constant pointer (typically either NULL or (LPCSTR)1, although some
58// check failures may include messages)
59//
60// NOTE: you should NEVER use the CHECK class API directly - use the macros below.
61//--------------------------------------------------------------------------------
62
63class SString;
64
65class CHECK
66{
67protected:
68 // On retail, this is a pointer to a string literal, null or (LPCSTR)1.
69 // On debug, this is a pointer to dynamically allocated memory - that
70 // lets us have formatted strings in debug builds.
71 LPCSTR m_message;
72
73#ifdef _DEBUG
74 LPCSTR m_condition;
75 LPCSTR m_file;
76 INT m_line;
77 LONG *m_pCount;
78
79 // Keep leakage counters.
80 static size_t s_cLeakedBytes;
81 static size_t s_cNumFailures;
82#endif
83
84 static BOOL s_neverEnforceAsserts;
85
86public: // !!! NOTE: Called from macros only!!!
87
88 // If we are not in a check, return TRUE and PushCheck; otherwise return FALSE
89 BOOL EnterAssert();
90
91 // Pops check count
92 void LeaveAssert();
93
94 // Just return if we are in a check
95 BOOL IsInAssert();
96
97 // Should we skip enforcing asserts
98 static BOOL EnforceAssert();
99
100 static BOOL EnforceAssert_StaticCheckOnly();
101
102 static void ResetAssert();
103
104#ifdef _MSC_VER
105#pragma warning(push)
106#pragma warning(disable:4702) // Disable bogus unreachable code warning
107#endif // _MSC_VER
108 CHECK() : m_message(NULL)
109#ifdef _DEBUG
110 , m_condition (NULL)
111 , m_file(NULL)
112 , m_line(NULL)
113 , m_pCount(NULL)
114#endif
115 {}
116#ifdef _MSC_VER
117#pragma warning(pop)
118#endif // _MSC_VER
119
120 // Fail records the result of a condition check. Can take either a
121 // boolean value or another check result
122 BOOL Fail(BOOL condition);
123 BOOL Fail(const CHECK &check);
124
125 // Setup records context info after a failure.
126 void Setup(LPCSTR message DEBUG_ARG(LPCSTR condition) DEBUG_ARG(LPCSTR file) DEBUG_ARG(INT line));
127 static LPCSTR FormatMessage(LPCSTR messageFormat, ...);
128
129 // Trigger triggers the actual check failure. The trigger may provide a reason
130 // to include in the failure message.
131 void Trigger(LPCSTR reason);
132
133 // Finally, convert to a BOOL to allow just testing the result of a Check function
134 operator BOOL();
135
136 BOOL operator!();
137
138 CHECK &operator()() { return *this; }
139
140 static inline const CHECK OK() {
141 return CHECK();
142 }
143
144 static void SetAssertEnforcement(BOOL value);
145
146 static void ReleaseTls(void* pCountTLS);
147
148 private:
149 static LONG* InitTls();
150#ifdef _DEBUG
151 static LPCSTR AllocateDynamicMessage(const SString &s);
152#endif
153};
154
155
156//--------------------------------------------------------------------------------
157// These CHECK macros are the correct way to propagate an assertion. These
158// routines are designed for use inside "Check" routines. Such routines may
159// be Invariants, Validate routines, or any other assertional predicates.
160//
161// A Check routine should return a value of type CHECK.
162//
163// It should consist of multiple CHECK or CHECK_MSG statements (along with appropritate
164// control flow) and should end with CHECK_OK() if all other checks pass.
165//
166// It may contain a CONTRACT_CHECK contract, but this is only appropriate if the
167// check is used for non-assertional purposes (otherwise the contract will never execute).
168// Note that CONTRACT_CHECK contracts do not support postconditions.
169//
170// CHECK: Check the given condition, return a CHECK failure if FALSE
171// CHECK_MSG: Same, but include a message paramter if the check fails
172// CHECK_OK: Return a successful check value;
173//--------------------------------------------------------------------------------
174
175#ifdef _DEBUG
176#define DEBUG_ONLY_MESSAGE(msg) msg
177#else
178// On retail, we don't want to add a bunch of string literals to the image,
179// so we just use the same one everywhere.
180#define DEBUG_ONLY_MESSAGE(msg) ((LPCSTR)1)
181#endif
182
183#define CHECK_MSG_EX(_condition, _message, _RESULT) \
184do \
185{ \
186 CHECK _check; \
187 if (_check.Fail(_condition)) \
188 { \
189 ENTER_DEBUG_ONLY_CODE; \
190 _check.Setup(DEBUG_ONLY_MESSAGE(_message) \
191 DEBUG_ARG(#_condition) \
192 DEBUG_ARG(__FILE__) \
193 DEBUG_ARG(__LINE__)); \
194 _RESULT(_check); \
195 LEAVE_DEBUG_ONLY_CODE; \
196 } \
197} while (0)
198
199#define RETURN_RESULT(r) return r
200
201#define CHECK_MSG(_condition, _message) \
202 CHECK_MSG_EX(_condition, _message, RETURN_RESULT)
203
204#define CHECK(_condition) \
205 CHECK_MSG(_condition, "")
206
207#define CHECK_MSGF(_condition, _args) \
208 CHECK_MSG(_condition, CHECK::FormatMessage _args)
209
210#define CHECK_FAIL(_message) \
211 CHECK_MSG(FALSE, _message); UNREACHABLE()
212
213#define CHECK_FAILF(_args) \
214 CHECK_MSGF(FALSE, _args); UNREACHABLE()
215
216#define CHECK_OK \
217 return CHECK::OK()
218
219//--------------------------------------------------------------------------------
220// ASSERT_CHECK is the proper way to trigger a check result. If the CHECK
221// has failed, the diagnostic assertion routines will fire with appropriate
222// context information.
223//
224// Note that the condition may either be a raw boolean expression or a CHECK result
225// returned from a Check routine.
226//
227// Recursion note: ASSERT_CHECKs are only performed if there is no current check in
228// progress.
229//--------------------------------------------------------------------------------
230
231#ifndef ENTER_DEBUG_ONLY_CODE
232#define ENTER_DEBUG_ONLY_CODE
233#endif
234
235#ifndef LEAVE_DEBUG_ONLY_CODE
236#define LEAVE_DEBUG_ONLY_CODE
237#endif
238
239#define ASSERT_CHECK(_condition, _message, _reason) \
240do \
241{ \
242 CHECK _check; \
243 if (_check.EnterAssert()) \
244 { \
245 ENTER_DEBUG_ONLY_CODE; \
246 if (_check.Fail(_condition)) \
247 { \
248 _check.Setup(_message \
249 DEBUG_ARG(#_condition) \
250 DEBUG_ARG(__FILE__) \
251 DEBUG_ARG(__LINE__)); \
252 _check.Trigger(_reason); \
253 } \
254 LEAVE_DEBUG_ONLY_CODE; \
255 _check.LeaveAssert(); \
256 } \
257} while (0)
258
259// ex: ASSERT_CHECKF(1+2==4, "my reason", ("Woah %d", 1+3));
260// note that the double parenthesis, the 'args' param below will include one pair of parens.
261#define ASSERT_CHECKF(_condition, _reason, _args) \
262 ASSERT_CHECK(_condition, CHECK::FormatMessage _args, _reason)
263
264//--------------------------------------------------------------------------------
265// INVARIANTS are descriptions of conditions which are always true at well defined
266// points of execution. Invariants may be checked by the caller or callee at any
267// time as paranoia requires.
268//
269// There are really two flavors of invariant. The "public invariant" describes
270// to the caller invariant behavior about the abstraction which is visible from
271// the public API (and of course it should be expressible in that public API).
272//
273// The "internal invariant" (or representation invariant), on the other hand, is
274// a description of the private implementation of the abstraction, which may examine
275// internal state of the abstraction or use private entry points.
276//
277// Classes with invariants should introduce methods called
278// void Invariant();
279// and
280// void InternalInvariant();
281// to allow invariant checks.
282//--------------------------------------------------------------------------------
283
284#if CHECK_INVARIANTS
285
286template <typename TYPENAME>
287CHECK CheckInvariant(TYPENAME &obj)
288{
289 __if_exists(TYPENAME::Invariant)
290 {
291 CHECK(obj.Invariant());
292 }
293 __if_exists(TYPENAME::InternalInvariant)
294 {
295 CHECK(obj.InternalInvariant());
296 }
297
298 CHECK_OK;
299}
300
301#define CHECK_INVARIANT(o) \
302 ASSERT_CHECK(CheckInvariant(o), NULL, "Invariant failure")
303
304#else
305
306#define CHECK_INVARIANT(o) do { } while (0)
307
308#endif
309
310//--------------------------------------------------------------------------------
311// VALIDATE is a check to be made on an object type which identifies a pointer as
312// a valid instance of the object, by calling CheckPointer on it. Normally a null
313// pointer is treated as an error; VALIDATE_NULL (or CheckPointer(o, NULL_OK))
314// may be used when a null pointer is acceptible.
315//
316// In addition to the null/non-null check, a type may provide a specific Check method
317// for more sophisticated identification. In general, the Check method
318// should answer the question
319// "Is this a valid instance of its declared compile-time type?". For instance, if
320// runtype type identification were supported for the type, it should be invoked here.
321//
322// Note that CheckPointer will also check the invariant(s) if appropriate, so the
323// invariants should NOT be explicitly invoked from the Check method.
324//--------------------------------------------------------------------------------
325
326enum IsNullOK
327{
328 NULL_NOT_OK = 0,
329 NULL_OK = 1
330};
331
332#if CHECK_INVARIANTS
333template <typename TYPENAME>
334CHECK CheckPointer(TYPENAME *o, IsNullOK ok = NULL_NOT_OK)
335{
336 if (o == NULL)
337 {
338 CHECK_MSG(ok, "Illegal null pointer");
339 }
340 else
341 {
342 __if_exists(TYPENAME::Check)
343 {
344 CHECK(o->Check());
345 }
346 }
347
348 CHECK_OK;
349}
350
351template <typename TYPENAME>
352CHECK CheckValue(TYPENAME &val)
353{
354 __if_exists(TYPENAME::Check)
355 {
356 CHECK(val.Check());
357 }
358
359 CHECK(CheckInvariant(val));
360
361 CHECK_OK;
362}
363#else // CHECK_INVARIANTS
364
365#ifdef _DEBUG_IMPL
366// Don't defined these functions to be nops for the non-debug
367// build as it may hide important checks
368template <typename TYPENAME>
369CHECK CheckPointer(TYPENAME *o, IsNullOK ok = NULL_NOT_OK)
370{
371 if (o == NULL)
372 {
373 CHECK_MSG(ok, "Illegal null pointer");
374 }
375
376 CHECK_OK;
377}
378
379template <typename TYPENAME>
380CHECK CheckValue(TYPENAME &val)
381{
382 CHECK_OK;
383}
384#endif
385
386#endif // CHECK_INVARIANTS
387
388#if VALIDATE_OBJECTS
389
390#define VALIDATE(o) \
391 ASSERT_CHECK(CheckPointer(o), "Validation failure")
392#define VALIDATE_NULL(o) \
393 ASSERT_CHECK(CheckPointer(o, NULL_OK), "Validation failure")
394
395#else
396
397#define VALIDATE(o) do { } while (0)
398#define VALIDATE_NULL(o) do { } while (0)
399
400#endif
401
402//--------------------------------------------------------------------------------
403// CONSISTENCY_CHECKS are ad-hoc assertions about the expected state of the program
404// at a given time. A failure in one of these indicates a bug in the code.
405//
406// Note that the condition may either be a raw boolean expression or a CHECK result
407// returned from a Check routine.
408//--------------------------------------------------------------------------------
409
410#define CONSISTENCY_CHECK(_condition) \
411 CONSISTENCY_CHECK_MSG(_condition, "")
412
413#ifdef _DEBUG_IMPL
414
415#define CONSISTENCY_CHECK_MSG(_condition, _message) \
416 ASSERT_CHECK(_condition, _message, "Consistency check failed")
417
418#define CONSISTENCY_CHECK_MSGF(_condition, args) \
419 ASSERT_CHECKF(_condition, "Consistency check failed", args)
420
421#else
422
423#define CONSISTENCY_CHECK_MSG(_condition, _message) do { } while (0)
424#define CONSISTENCY_CHECK_MSGF(_condition, args) do { } while (0)
425
426#endif
427
428//--------------------------------------------------------------------------------
429// SIMPLIFYING_ASSUMPTIONS are workarounds which are placed in the code to allow progress
430// to be made in the case of difficult corner cases. These should NOT be left in the
431// code; they are really just markers of things which need to be fixed.
432//
433// Note that the condition may either be a raw boolean expression or a CHECK result
434// returned from a Check routine.
435//--------------------------------------------------------------------------------
436
437// Ex usage:
438// SIMPLIFYING_ASSUMPTION(SomeExpression());
439#define SIMPLIFYING_ASSUMPTION(_condition) \
440 SIMPLIFYING_ASSUMPTION_MSG(_condition, "")
441
442
443// Helper for HRs. Will provide formatted message showing the failure code.
444#define SIMPLIFYING_ASSUMPTION_SUCCEEDED(__hr) \
445 { \
446 HRESULT __hr2 = (__hr); \
447 (void)__hr2; \
448 SIMPLIFYING_ASSUMPTION_MSGF(SUCCEEDED(__hr2), ("HRESULT failed.\n Expected success.\n Actual=0x%x\n", __hr2)); \
449 }
450
451#ifdef _DEBUG_IMPL
452
453// Ex usage:
454// SIMPLIFYING_ASSUMPTION_MSG(SUCCEEDED(hr), "It failed!");
455#define SIMPLIFYING_ASSUMPTION_MSG(_condition, _message) \
456 ASSERT_CHECK(_condition, _message, "Unhandled special case detected")
457
458// use a formatted string. Ex usage:
459// SIMPLIFYING_ASSUMPTION_MSGF(SUCCEEDED(hr), ("Woah it failed! 0x%08x", hr));
460#define SIMPLIFYING_ASSUMPTION_MSGF(_condition, args) \
461 ASSERT_CHECKF(_condition, "Unhandled special case detected", args)
462
463#else // !_DEBUG_IMPL
464
465#define SIMPLIFYING_ASSUMPTION_MSG(_condition, _message) do { } while (0)
466#define SIMPLIFYING_ASSUMPTION_MSGF(_condition, args) do { } while (0)
467
468#endif // !_DEBUG_IMPL
469
470//--------------------------------------------------------------------------------
471// COMPILER_ASSUME_MSG is a statement that tells the compiler to assume the
472// condition is true. In a checked build these turn into asserts;
473// in a free build they are passed through to the compiler to use in optimization.
474//--------------------------------------------------------------------------------
475
476#if defined(_PREFAST_) || defined(_PREFIX_)
477#define COMPILER_ASSUME_MSG(_condition, _message) if (!(_condition)) __UNREACHABLE();
478#define COMPILER_ASSUME_MSGF(_condition, args) if (!(_condition)) __UNREACHABLE();
479#else
480
481#if defined(DACCESS_COMPILE)
482#define COMPILER_ASSUME_MSG(_condition, _message) do { } while (0)
483#define COMPILER_ASSUME_MSGF(_condition, args) do { } while (0)
484#else
485
486#if defined(_DEBUG)
487#define COMPILER_ASSUME_MSG(_condition, _message) \
488 ASSERT_CHECK(_condition, _message, "Compiler optimization assumption invalid")
489#define COMPILER_ASSUME_MSGF(_condition, args) \
490 ASSERT_CHECKF(_condition, "Compiler optimization assumption invalid", args)
491#else
492#define COMPILER_ASSUME_MSG(_condition, _message) __assume(_condition)
493#define COMPILER_ASSUME_MSGF(_condition, args) __assume(_condition)
494#endif // _DEBUG
495
496#endif // DACCESS_COMPILE
497
498#endif // _PREFAST_ || _PREFIX_
499
500
501#define COMPILER_ASSUME(_condition) \
502 COMPILER_ASSUME_MSG(_condition, "")
503
504
505//--------------------------------------------------------------------------------
506// PREFIX_ASSUME_MSG and PREFAST_ASSUME_MSG are just another name
507// for COMPILER_ASSUME_MSG
508// In a checked build these turn into asserts; in a free build
509// they are passed through to the compiler to use in optimization;
510// via an __assume(_condition) optimization hint.
511//--------------------------------------------------------------------------------
512
513#define PREFIX_ASSUME_MSG(_condition, _message) \
514 COMPILER_ASSUME_MSG(_condition, _message)
515
516#define PREFIX_ASSUME_MSGF(_condition, args) \
517 COMPILER_ASSUME_MSGF(_condition, args)
518
519#define PREFIX_ASSUME(_condition) \
520 COMPILER_ASSUME_MSG(_condition, "")
521
522#define PREFAST_ASSUME_MSG(_condition, _message) \
523 COMPILER_ASSUME_MSG(_condition, _message)
524
525#define PREFAST_ASSUME_MSGF(_condition, args) \
526 COMPILER_ASSUME_MSGF(_condition, args)
527
528#define PREFAST_ASSUME(_condition) \
529 COMPILER_ASSUME_MSG(_condition, "")
530
531//--------------------------------------------------------------------------------
532// UNREACHABLE points are locations in the code which should not be able to be
533// reached under any circumstances (e.g. a default in a switch which is supposed to
534// cover all cases.). This macro tells the compiler this, and also embeds a check
535// to make sure it is always true.
536//--------------------------------------------------------------------------------
537
538#define UNREACHABLE() \
539 UNREACHABLE_MSG("")
540
541#ifdef __llvm__
542
543// LLVM complains if a function does not return what it says.
544#define UNREACHABLE_RET() do { UNREACHABLE(); return 0; } while (0)
545#define UNREACHABLE_MSG_RET(_message) UNREACHABLE_MSG(_message); return 0;
546
547#else // __llvm__
548
549#define UNREACHABLE_RET() UNREACHABLE()
550#define UNREACHABLE_MSG_RET(_message) UNREACHABLE_MSG(_message)
551
552#endif // __llvm__ else
553
554#if defined(_MSC_VER) || defined(_PREFIX_)
555#if defined(_TARGET_AMD64_)
556// Empty methods that consist of UNREACHABLE() result in a zero-sized declspec(noreturn) method
557// which causes the pdb file to make the next method declspec(noreturn) as well, thus breaking BBT
558// Remove when we get a VC compiler that fixes VSW 449170
559# define __UNREACHABLE() DebugBreak(); __assume(0);
560#else
561# define __UNREACHABLE() __assume(0)
562#endif
563#else
564#define __UNREACHABLE() do { } while(true)
565#endif
566
567#ifdef _DEBUG_IMPL
568
569// Note that the "do { } while (0)" syntax trick here doesn't work, as the compiler
570// gives an error that the while(0) is unreachable code
571#define UNREACHABLE_MSG(_message) \
572{ \
573 CHECK _check; \
574 _check.Setup(_message, "<unreachable>", __FILE__, __LINE__); \
575 _check.Trigger("Reached the \"unreachable\""); \
576} __UNREACHABLE()
577
578#else
579
580#define UNREACHABLE_MSG(_message) __UNREACHABLE()
581
582#endif
583
584
585//--------------------------------------------------------------------------------
586// STRESS_CHECK represents a check which is included in a free build
587// @todo: behavior on trigger
588//
589// Note that the condition may either be a raw boolean expression or a CHECK result
590// returned from a Check routine.
591//
592// Since Retail builds don't allow formatted checks, there's no STRESS_CHECK_MSGF.
593//--------------------------------------------------------------------------------
594
595#if CHECK_STRESS
596
597#define STRESS_CHECK(_condition, _message) \
598 ASSERT_CHECK(_condition, _message, "Stress Assertion Failure")
599
600#else
601
602#define STRESS_CHECK(_condition, _message) do { } while (0)
603
604#endif
605
606//--------------------------------------------------------------------------------
607// CONTRACT_CHECK is used to put contracts on Check function. Note that it does
608// not support postconditions.
609//--------------------------------------------------------------------------------
610
611#define CONTRACT_CHECK CONTRACTL
612#define CONTRACT_CHECK_END CONTRACTL_END
613
614//--------------------------------------------------------------------------------
615// CCHECK is used for Check functions which may fail due to out of memory
616// or other transient failures. These failures should be ignored when doing
617// assertions, but they cannot be ignored when the Check function is used in
618// normal code.
619// @todo: really crufty to have 2 sets of CHECK macros
620//--------------------------------------------------------------------------------
621
622#ifdef _DEBUG
623
624#define CCHECK_START \
625 { \
626 BOOL ___exception = FALSE; \
627 BOOL ___transient = FALSE; \
628 CHECK ___result = CHECK::OK(); \
629 EX_TRY {
630
631#define CCHECK_END \
632 } EX_CATCH { \
633 if (___result.IsInAssert()) \
634 { \
635 ___exception = TRUE; \
636 ___transient = GET_EXCEPTION()->IsTransient(); \
637 } \
638 else \
639 EX_RETHROW; \
640 } EX_END_CATCH(RethrowTerminalExceptions); \
641 \
642 if (___exception) \
643 { \
644 if (___transient) \
645 CHECK_OK; \
646 else \
647 CHECK_FAIL("Nontransient exception occurred during check"); \
648 } \
649 CHECK(___result); \
650 }
651
652#define CRETURN_RESULT(r) ___result = r
653
654#define CCHECK_MSG(_condition, _message) \
655 CHECK_MSG_EX(_condition, _message, CRETURN_RESULT)
656
657#define CCHECK(_condition) \
658 CCHECK_MSG(_condition, "")
659
660#define CCHECK_MSGF(_condition, _args) \
661 CCHECK_MSG(_condition, CHECK::FormatMessage _args)
662
663#define CCHECK_FAIL(_message) \
664 CCHECK_MSG(FALSE, _message); UNREACHABLE()
665
666#define CCHECK_FAILF(_args) \
667 CCHECK_MSGF(FALSE, _args); UNREACHABLE()
668
669#else // _DEBUG
670
671#define CCHECK_START
672#define CCHECK_END
673
674#define CCHECK CHECK
675#define CCHECK_MSG CHECK_MSG
676#define CCHECK_MSGF CHECK_MSGF
677#define CCHECK_FAIL CHECK_FAIL
678#define CCHECK_FAILF CHECK_FAILF
679
680#endif
681
682
683
684//--------------------------------------------------------------------------------
685// Common base level checks
686//--------------------------------------------------------------------------------
687
688CHECK CheckAlignment(UINT alignment);
689
690CHECK CheckAligned(UINT value, UINT alignment);
691#if defined(_MSC_VER)
692CHECK CheckAligned(ULONG value, UINT alignment);
693#endif
694CHECK CheckAligned(UINT64 value, UINT alignment);
695CHECK CheckAligned(const void *address, UINT alignment);
696
697CHECK CheckOverflow(UINT value1, UINT value2);
698#if defined(_MSC_VER)
699CHECK CheckOverflow(ULONG value1, ULONG value2);
700#endif
701CHECK CheckOverflow(UINT64 value1, UINT64 value2);
702CHECK CheckOverflow(PTR_CVOID address, UINT offset);
703#if defined(_MSC_VER)
704CHECK CheckOverflow(const void *address, ULONG offset);
705#endif
706CHECK CheckOverflow(const void *address, UINT64 offset);
707
708CHECK CheckUnderflow(UINT value1, UINT value2);
709#if defined(_MSC_VER)
710CHECK CheckUnderflow(ULONG value1, ULONG value2);
711#endif
712CHECK CheckUnderflow(UINT64 value1, UINT64 value2);
713CHECK CheckUnderflow(const void *address, UINT offset);
714#if defined(_MSC_VER)
715CHECK CheckUnderflow(const void *address, ULONG offset);
716#endif
717CHECK CheckUnderflow(const void *address, UINT64 offset);
718CHECK CheckUnderflow(const void *address, void *address2);
719
720CHECK CheckZeroedMemory(const void *memory, SIZE_T size);
721
722// These include overflow checks
723CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset);
724CHECK CheckBounds(const void *rangeBase, UINT32 rangeSize, UINT32 offset, UINT32 size);
725
726void WINAPI ReleaseCheckTls(LPVOID pTlsData);
727
728// ================================================================================
729// Inline definitions
730// ================================================================================
731
732#include "check.inl"
733
734#endif // CHECK_H_
735