summaryrefslogtreecommitdiff
path: root/src/inc/contract.h
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2016-11-23 10:09:09 (GMT)
committerJiyoung Yun <jy910.yun@samsung.com>2016-11-23 10:09:09 (GMT)
commit4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch)
tree98110734c91668dfdbb126fcc0e15ddbd93738ca /src/inc/contract.h
parentfa45f57ed55137c75ac870356a1b8f76c84b229c (diff)
downloadcoreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/inc/contract.h')
-rw-r--r--src/inc/contract.h2598
1 files changed, 2598 insertions, 0 deletions
diff --git a/src/inc/contract.h b/src/inc/contract.h
new file mode 100644
index 0000000..dd66d2a
--- /dev/null
+++ b/src/inc/contract.h
@@ -0,0 +1,2598 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ---------------------------------------------------------------------------
+// Contract.h
+//
+
+// ! I am the owner for issues in the contract *infrastructure*, not for every
+// ! CONTRACT_VIOLATION dialog that comes up. If you interrupt my work for a routine
+// ! CONTRACT_VIOLATION, you will become the new owner of this file.
+//--------------------------------------------------------------------------------
+// CONTRACTS - User Reference
+//
+// A CONTRACT is a container for a set of checked declarations about a
+// function. Besides giving developers a "laundry list" of checks to
+// make checking more complete, contracts compile these checks
+// as hidden annotations into the checked executable that our static scanner
+// uses to detect violations automatically.
+//
+// Contracts can be dynamic or static. Dynamic contracts perform runtime checks
+// as well as being visible to the static scanner. Static contracts generate no
+// runtime code but are still visible to the scanner. Dynamic contracts are
+// preferred unless perf or other considerations preclude them.
+//
+// The following annotations can appear in contracts:
+//
+//
+// THROWS an exception might be thrown out of the function
+// -or- NOTHROW an exception will NOT be thrown out of the function
+//
+//
+//
+// INJECT_FAULT(statement) function might require its caller to handle an OOM
+// -or- FAULT_FORBID function will NOT require its caller to handle an OOM
+//
+//
+//
+// GC_TRIGGERS the function can trigger a GC
+// -or- GC_NOTRIGGER the function will never trigger a GC provided its
+// called in coop mode.
+//
+//
+// MODE_COOPERATIVE the function requires Cooperative GC mode on entry
+// -or- MODE_PREEMPTIVE the function requires Preemptive GC mode on entry
+// -or- MODE_ANY the function can be entered in either mode
+//
+// LOADS_TYPE(level) the function promises not to load any types beyond "level"
+//
+// SO_INTOLERANT the function cannot tolerate an SO at any point and must run behind an
+// an SO probe via BEGIN_SO_INTOLERANT_XXX. This is the default. We want most
+// of our code to run behind an SO probe. The only time you need to explicitly
+// mark something as SO_INTOLERANT is if the static analysis tool incorrectly
+// flags it as an entry point.
+// -or- SO_TOLERANT the function can tolerate an SO. It either does not update any global state
+// that needs to be cleaned up should a random SO occur, or it protects those
+// updates behind an SO probe.
+// -or- SO_NOT_MAINLINE the function is not hardened to SO and should never run on a managed thread
+// where we need to be hardened to SO. You can use this for functions that run
+// only for ngen or Win9X etc.
+//
+// CAN_TAKE_LOCK the function has a code path that takes a lock
+// _or_ (CAN_TAKE_LOCK and CANNOT_RETAKE_LOCK)
+// the function has a code path that takes a lock, but never tries to reenter
+// locks held at the time this function was called.
+// -or- CANNOT_TAKE_LOCK the function will never allow a lock to be taken
+// -or- the default is WRAPPER(CAN_TAKE_LOCK). i.e., if any callees take locks,
+// then it's ok for this function to as well. If LIMITED_METHOD_CONTRACT is specified,
+// however, then CANNOT_TAKE_LOCK is assumed.
+//
+// EE_THREAD_NOT_REQUIRED the function does not assume an EE Thread object is available in TLS.
+// Either GetThread() is never called, or any code path that requires a Thread
+// has another code path that deals with the absence of a Thread. Any call to
+// to GetThread() must be bracketed with BEGIN_GETTHREAD_ALLOWED /
+// END_GETTHREAD_ALLOWED to avoid bogus asserts (the short-form
+// GetThreadNULLOk() may be used as well). However, this is only allowed if visual
+// inspection of the call site makes it patently obvious that the function deals
+// appropriately with the GetThread() == NULL case.
+// -or- EE_THREAD_REQUIRED the function requires an EE Thread object in TLS (i.e., GetThread() != NULL)
+// If this contract is used, we will ASSERT on entry to the function that
+// GetThread() != NULL.
+// -or- the default is DISABLED(EE_THREAD_REQUIRED). i.e., we do not assert
+// GetThread() != NULL on entry to the function and do not assert on any
+// unprotected uses of GetThread().
+// See code:GetThreadGenericFullCheck for info on how these
+// contracts are enforced.
+//
+// SUPPORTS_DAC The function has been written to be callable from out-of-process using DAC.
+// In builds where DACCESS_COMPILE is defined, such functions can only call
+// other such functions (and a few primitives like new). Functions that support
+// DAC must be carefully written to conform to the rules in daccess.h.
+//
+// SUPPORTS_DAC_HOST_ONLY The function and its call graph has been written to be callable from out of process
+// using DAC, but it differs from SUPPORTS_DAC in that these functions won't perform
+// any marshalling. Because it does no marshalling, SUPPORTS_DAC_HOST_ONLY functions
+// and their call graph won't be checked by DacCop. This should only be used by utility
+// functions which will never marshal anything.
+//
+// PRECONDITION(X) - generic CHECK or BOOL expression which should be true
+// on function entry
+//
+// POSTCONDITION(X) - generic CHECK or BOOL expression which should be true
+// on function entry. Note that variable RETVAL will be
+// available for use in the expression.
+//
+//
+// INSTANCE_CHECK - equivalent of:
+// PRECONDITION(CheckPointer(this));
+// POSTCONDITION(CheckInvariant(this));
+// INSTANCE_CHECK_NULL - equivalent of:
+// PRECONDITION(CheckPointer(this, NULL_OK));
+// POSTCONDITION(CheckInvariant(this, NULL_OK));
+// CONSTRUCTOR_CHECK - equivalent of:
+// POSTCONDITION(CheckPointer(this));
+// DESTRUCTOR_CHECK - equivalent of:
+// PRECONDITION(CheckPointer(this));
+//
+//
+//
+//
+// Contracts come in the following flavors:
+//
+// Dynamic:
+// CONTRACTL the standard version used for all dynamic contracts
+// except those including postconditions.
+//
+// CONTRACT(rettype) an uglier version of CONTRACTL that's unfortunately
+// needed to support postconditions. You must specify
+// the correct return type and it cannot be "void."
+// (Use CONTRACT_VOID instead) You must use the
+// RETURN macro rather than the "return" keyword.
+//
+// CONTRACT_VOID you can't supply "void" to a CONTRACT - use this
+// instead.
+//
+// Static:
+// LIMITED_METHOD_CONTRACT
+// A static contract equivalent to NOTHROW/GC_NOTRIGGER/FORBID_FAULT/MODE_ANY.
+// Use only for trivial functions that call only functions with LIMITED_METHOD_CONTRACTs
+// (as long as there is no cycle that may introduce infinite recursion).
+//
+// STATIC_CONTRACT_THROWS
+// STATIC_CONTRACT_NOTHROW
+// STATIC_CONTRACT_GC_TRIGGERS
+// STATIC_CONTRACT_GCNOTRIGGER
+// STATIC_CONTRACT_FAULT
+// STATIC_CONTRACT_FORBID_FAULT
+// STATIC_CONTRACT_SO_INTOLERANT
+// STATIC_CONTRACT_SO_TOLERANT
+// STATIC_CONTRACT_SO_NOT_MAINLINE
+// use to implement statically checkable contracts
+// when runtime contracts cannot be used.
+//
+//
+// WRAPPER(annotation)
+//
+// When a function does not explicitly caused a condition, use the WRAPPER macro around
+// the declaration. This implies that the function is dependent on the functions it calls
+// for its behaviour, and guarantees nothing.
+//
+//
+// CONTRACT_VIOLATION(violationmask):
+//
+// A bandaid used to suppress contract assertions. A contract violation
+// is always a bug and you're expected to remove it before shipping.
+// If a violation cannot be fixed immediately, however, it's better
+// to use this on the offending callsite than to disable a contract entirely.
+//
+// The violationmask can be one or more of the following OR'd together.
+//
+// ThrowsViolation
+// GCViolation
+// ModeViolation
+// FaultViolation
+// SOToleranceViolation
+// FaultNotFatal
+// HostViolation
+// LoadsTypeViolation
+// TakesLockViolation
+//
+// The associated assertion will be suppressed until you leave the scope
+// containing the CONTRACT_VIOLATION. Note, however, that any called
+// function that redeclares the associated annotation reinstates
+// the assert for the scope of *its* call. This prevents a CONTRACT_VIOLATION
+// placed at the root of a calltree from decimating our entire protection.
+//
+//
+// PERMANENT_CONTRACT_VIOLATION(violationmask, permanentContractViolationReason):
+//
+// Like a CONTRACT_VIOLATION but also indicates that the violation was a deliberate decision
+// and we don't plan on removing the violation in the next release. The reason
+// for the violation should be given as the second parameter to the macro. Reasons
+// are currently for documentation purposes only and do not have an effect on the binary.
+// Valid values are listed below in the definition of PermanentContractViolationReason.
+//
+//
+// CONDITIONAL_CONTRACT_VIOLATION(violationmask, condition):
+//
+// Similar to CONTRACT_VIOLATION, but only suppresses the contract if the
+// condition evaluates to non-zero. The need for this macro should be very
+// rare, but it can be useful if a contract should be suppressed based on a
+// condition known only at run-time. For example, if a particular test causes
+// call sequences never expected by real scenarios, you may want to suppress
+// resulting violations, but only when that test is run.
+//
+// WRAPPER_NO_CONTRACT
+//
+// A do-nothing contract used by functions that trivially wrap another.
+//
+//
+// "LEGACY" stuff - these features have been mostly superceded by better solutions
+// so their use should be discouraged.
+//
+//
+// DISABLED(annotation)
+//
+// Indicates that a condition is supposed to be checked but is being suppressed
+// due to some temporary bug. The more surgical CONTRACT_VIOLATION is
+// preferred over DISABLED.
+//
+// UNCHECKED(annotation)
+//
+// Indicates that a condition is supposed to be checked but is being suppressed
+// due for perf reasons. Use STATIC_CONTRACT over this.
+//
+//
+// Default values:
+// If you don't specify certain annotaions, you get defaults.
+// - THROWS/NOTHROW defaults to THROWS
+// - GCTRIGGERS/GCNOTRIGGER defaults to GCTRIGGERS within the VM directory
+// and to no check otherwise
+// - INJECT/FORBID_FAULT defaults to no check
+// - MODE defaults to MODE_ANY
+//
+// The problem is that defaults don't work well with static contracts.
+// The scanner will always treat a missing annotation as DISABLED.
+// New code should not rely on defaults. Explicitly state your invariants.
+//
+//
+//--------------------------------------------------------------------------------
+
+
+
+
+#ifndef CONTRACT_H_
+#define CONTRACT_H_
+
+#ifdef _MSC_VER
+#pragma warning(disable:4189) //local variable is initialized but not referenced
+#endif
+
+
+// We only enable contracts in _DEBUG builds
+#if defined(_DEBUG) && !defined(DISABLE_CONTRACTS)
+#define ENABLE_CONTRACTS_DATA
+#endif
+
+// Also, we won't enable contracts if this is a DAC build.
+// @ARMTODO: Disable for ARM for now, contracts slow down the debug build far too much
+#if defined(ENABLE_CONTRACTS_DATA) && !defined(DACCESS_COMPILE) && !defined(CROSS_COMPILE) && !defined(_TARGET_ARM_)
+#define ENABLE_CONTRACTS
+#endif
+
+// Finally, only define the implementaiton parts of contracts if this isn't a DAC build.
+#if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS)
+#define ENABLE_CONTRACTS_IMPL
+#endif
+
+#include "specstrings.h"
+#include "clrtypes.h"
+#include "malloc.h"
+#include "check.h"
+#include "debugreturn.h"
+#include "staticcontract.h"
+
+#ifdef ENABLE_CONTRACTS_DATA
+
+#include "eh.h"
+
+// We chain these onto a stack to give us a stack trace of contract assertions (useful
+// when the bug report doesn't contain valid symbols)
+
+struct ContractStackRecord
+{
+ ContractStackRecord *m_pNext;
+ const char *m_szFunction;
+ const char *m_szFile;
+ int m_lineNum;
+ UINT m_testmask; // Bitmask of Contract::TestEnum bitsf
+ const char *m_construct; // The syntactic construct that pushed this thing
+};
+
+class CrstBase;
+
+// The next few enums / structs are used to keep track of all kinds of locks
+// currently taken by the current thread (crsts, spinlocks, CLR critical sections).
+// Across the VM, there are still multiple counts of locks. The lock counts in these
+// contract structs are used to verify consistency of lock take/release in EE code, and
+// for contracts. Both user and EE locks are tracked here, but it's EE code consistency
+// we're verifying. The Thread object keeps its own counts as well, primarily of user
+// locks for implementing thread abort & escalation policy. We tried to have the Thread
+// counts also be used for consistency checking, but that doesn't work. Thread counters
+// have the following behavior that hurts our internal consistency checks:
+// - They only count user locks.
+// - Counters are reset & restored as we leave and return to AppDomains
+
+// An array of these is stored in DbgStateLockData::m_rgTakenLockInfos
+// to remember which locks we've taken. If you hit an assert that
+// indicates we're exiting locks in the wrong order, or that locks were
+// taken when we expected none to be taken, then you can use
+// DbgStateLockData::m_rgTakenLockInfos to see the locks we know about.
+struct TakenLockInfo
+{
+ // Generally, this will be a pointer to the lock, but really it's just
+ // a value that identifies which lock is taken. Ya see, sometimes we don't
+ // have a lock pointer handy (e.g., if the lock is based on a GC object,
+ // which has no persistent object pointer we can use). Look at the source
+ // indicated by m_szFile / m_lineNum to see what was specified as m_pvLock.
+ //
+ // A common case is that the lock is just a Crst, so to aid debugging, we
+ // also include a statically typed version of this pointer (m_pCrstBase) just
+ // for Crsts. Again, you'll want look at m_szFile / m_lineNum to see how to
+ // interpret this union.
+ union
+ {
+ void * m_pvLock;
+ CrstBase * m_pCrstBase;
+ };
+
+ // File & line of the *LOCK_TAKEN* macro that added this lock to our list
+ const char * m_szFile;
+ int m_lineNum;
+};
+
+enum DbgStateLockType
+{
+ // EE locks (used to sync EE structures). These do not include
+ // CRST_HOST_BREAKABLE Crsts, and are thus not held while managed
+ // code runs
+ kDbgStateLockType_EE,
+
+ // CRST_HOST_BREAKABLE Crsts. These can be held while arbitrary
+ // managed code runs.
+ kDbgStateLockType_HostBreakableCrst,
+
+ // User locks (e.g., Monitor.Enter, ReaderWriterLock class)
+ kDbgStateLockType_User,
+
+ // add more lock types here
+
+ kDbgStateLockType_Count
+};
+
+// This keeps track of how many locks, and which locks, are currently owned
+// by the current thread. There is one instance of this structure per
+// thread (no EE Thread object required). This is in contrast to the
+// ClrDebugState structure, which is instantiated once per function
+// on the stack. Reason is that ClrDebugState resets its state on exit
+// of function (Contract destructor reinstates previous ClrDebugState), whereas
+// we want DbgStateLockData to persist across function enters & exits.
+struct DbgStateLockData
+{
+ // When a lock is taken, we keep track of its pointer and file/line# when it
+ // was added in a static-size array DbgStateLockData::m_rgTakenLockInfos. This is
+ // the size of that array, and therefore indicates the maximum number of locks we
+ // expect one thread to hold at the same time. If we should exceed this limit,
+ // we'll lose this data for the latter locks that exceed this limit
+ // (though still maintaining an accurate *count* of locks).
+ static const int kMaxAllowedSimultaneousLocks = 20;
+
+ // Count of locks taken, separately by type
+ UINT m_rgcLocksTaken[kDbgStateLockType_Count];
+
+ // List of the specific locks that have been taken (all DbgStateLockTypes
+ // intermingled), in the order they were taken. If we exceed the elements
+ // in the array, we just won't track the latter locks in here (though they are
+ // included in the counts above)
+ TakenLockInfo m_rgTakenLockInfos[kMaxAllowedSimultaneousLocks];
+
+ void SetStartingValues();
+ void LockTaken(DbgStateLockType dbgStateLockType,
+ UINT cEntrances,
+ void * pvLock,
+ __in_z const char * szFunction,
+ __in_z const char * szFile,
+ int lineNum);
+ void LockReleased(DbgStateLockType dbgStateLockType, UINT cExits, void * pvLock);
+ UINT GetLockCount(DbgStateLockType dbgStateLockType);
+ UINT GetCombinedLockCount();
+};
+
+// This struct contains all lock contract information. It is created and destroyed along with
+// ClrDebugState. m_pLockData points to a DbgStateLockData object that is allocated per thread
+// and persists across function enters and exists.
+struct DbgStateLockState
+{
+private:
+ // Count of locks taken at the time the function with CANNOT_RETAKE_LOCK contract
+ // was called
+ UINT m_cLocksEnteringCannotRetakeLock;
+
+ DbgStateLockData * m_pLockData; // How many and which locks are currently taken on this thread
+
+public:
+ void SetStartingValues();
+ void OnEnterCannotRetakeLockFunction();
+ BOOL IsLockRetaken(void * pvLock);
+ BOOL IsSafeToRelease(UINT cReleases);
+ void SetDbgStateLockData(DbgStateLockData * pDbgStateLockData);
+ DbgStateLockData * GetDbgStateLockData();
+};
+
+
+#define CONTRACT_BITMASK_OK_TO_THROW 0x1 << 0
+#define CONTRACT_BITMASK_FAULT_FORBID 0x1 << 1
+#define CONTRACT_BITMASK_HOSTCALLS 0x1 << 2
+#define CONTRACT_BITMASK_SOTOLERANT 0x1 << 3
+#define CONTRACT_BITMASK_DEBUGONLY 0x1 << 4
+#define CONTRACT_BITMASK_SONOTMAINLINE 0x1 << 5
+#define CONTRACT_BITMASK_ALLOWGETTHREAD 0x1 << 6
+#define CONTRACT_BITMASK_OK_TO_LOCK 0x1 << 7
+#define CONTRACT_BITMASK_OK_TO_RETAKE_LOCK 0x1 << 8
+
+
+#define CONTRACT_BITMASK_IS_SET(whichbit) ((m_flags & (whichbit)) != 0)
+#define CONTRACT_BITMASK_SET(whichbit) (m_flags |= (whichbit))
+#define CONTRACT_BITMASK_RESET(whichbit) (m_flags &= ~(whichbit))
+#define CONTRACT_BITMASK_UPDATE(whichbit, value) ((value)?CONTRACT_BITMASK_SET(whichbit):CONTRACT_BITMASK_RESET(whichbit))
+
+
+// Stored in the FLS under TlsIdx_ClrDebugState.
+struct ClrDebugState
+{
+private:
+ UINT_PTR m_flags;
+ UINT_PTR m_violationmask; // Current CONTRACT_VIOLATIONS in effect
+ ContractStackRecord *m_pContractStackTrace;
+ UINT m_GCNoTriggerCount;
+ UINT m_GCForbidCount;
+ UINT m_maxLoadTypeLevel; // taken from enum ClassLoadLevel
+ BOOL m_allowGetThread; // TRUE if GetThread() is ok in this scope
+#ifdef FEATURE_STACK_PROBE //StackMarkerStack required only when SO infrastructure is enabled
+ /* Used to validate backout stack consumption required for StackOverflow infrastructure */
+ StackMarkerStack m_StackMarkerStack; // The stack of stack markers
+#endif
+ DbgStateLockState m_LockState;
+
+public:
+ // Use an explicit Init rather than ctor as we don't want automatic
+ // construction of the ClrDebugState embedded inside the contract.
+ void SetStartingValues()
+ {
+ m_violationmask = 0; // No violations allowed
+
+ // Default is we're in a THROWS scope. This is not ideal, but there are
+ // just too many places that I'd have to go clean up right now
+ // (hundreds) in order to make this FALSE by default.
+ // Faults not forbidden (an unfortunate default but
+ // we'd never get this debug infrastructure bootstrapped otherwise.)
+ // We start out in SO-tolerant mode and must probe before entering SO-intolerant
+ // any global state updates.
+ // Initial mode is non-debug until we say otherwise
+ // Everthing defaults to mainline
+ // By default, GetThread() is perfectly fine to call
+ // By default, it's ok to take a lock (or call someone who does)
+ m_flags = CONTRACT_BITMASK_OK_TO_THROW|
+ CONTRACT_BITMASK_HOSTCALLS|
+ CONTRACT_BITMASK_SOTOLERANT|
+ CONTRACT_BITMASK_ALLOWGETTHREAD|
+ CONTRACT_BITMASK_OK_TO_LOCK|
+ CONTRACT_BITMASK_OK_TO_RETAKE_LOCK;
+
+ m_pContractStackTrace = NULL; // At top of stack, no contracts in force
+ m_GCNoTriggerCount = 0;
+ m_GCForbidCount = 0;
+
+ m_maxLoadTypeLevel = ((UINT)(-1)); // ideally CLASS_LOAD_LEVEL_FINAL but we don't have access to that #define, so
+ // the max integer value will do as a substitute.
+
+ m_allowGetThread = TRUE; // By default, GetThread() is perfectly fine to call
+
+#ifdef FEATURE_STACK_PROBE
+ m_StackMarkerStack.Init();
+#endif
+
+ m_LockState.SetStartingValues();
+ }
+
+ void CheckOkayToThrow(__in_z const char *szFunction, __in_z const char *szFile, int lineNum); // Asserts if its not okay to throw.
+ BOOL CheckOkayToThrowNoAssert(); // Returns if OK to throw
+
+ //--//
+
+ UINT_PTR* ViolationMaskPtr()
+ {
+ return &m_violationmask;
+ }
+
+ UINT_PTR ViolationMask()
+ {
+ return m_violationmask;
+ }
+
+ void ViolationMaskSet( UINT_PTR value )
+ {
+ m_violationmask |= value;
+ }
+
+ void ViolationMaskReset( UINT_PTR value )
+ {
+ m_violationmask &= ~value;
+ }
+
+ //--//
+
+ BOOL IsOkToThrow()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_THROW);
+ }
+
+ void SetOkToThrow()
+ {
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_OK_TO_THROW);
+ }
+
+ BOOL SetOkToThrow( BOOL value )
+ {
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_THROW);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_OK_TO_THROW, value);
+ return prevState;
+ }
+
+ void ResetOkToThrow()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_OK_TO_THROW);
+ }
+ //--//
+
+ BOOL IsFaultForbid()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_FAULT_FORBID);
+ }
+
+
+ void SetFaultForbid()
+ {
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_FAULT_FORBID);
+ }
+
+ BOOL SetFaultForbid(BOOL value)
+ {
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_FAULT_FORBID);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_FAULT_FORBID, value);
+ return prevState;
+ }
+
+ void ResetFaultForbid()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_FAULT_FORBID);
+ }
+
+ //--//
+ BOOL IsHostCaller()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_HOSTCALLS);
+ }
+
+ void SetHostCaller()
+ {
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_HOSTCALLS);
+ }
+
+
+ BOOL SetHostCaller(BOOL value)
+ {
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_HOSTCALLS);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_HOSTCALLS,value);
+ return prevState;
+ }
+
+ void ResetHostCaller()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_HOSTCALLS);
+ }
+
+#ifdef FEATURE_STACK_PROBE //SO contract functions only required when SO infrastructure is enabled
+ //--//
+ BOOL IsSOTolerant()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_SOTOLERANT);
+ }
+
+ void SetSOTolerance()
+ {
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_SOTOLERANT);
+ }
+
+ BOOL SetSOTolerance(BOOL tolerance)
+ {
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_SOTOLERANT);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_SOTOLERANT,tolerance);
+ return prevState;
+ }
+
+ void ResetSOTolerance()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_SOTOLERANT);
+ }
+
+#endif
+
+ //--//
+ BOOL IsDebugOnly()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_DEBUGONLY);
+ }
+
+ void SetDebugOnly()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_DEBUGONLY);
+ }
+
+ BOOL SetDebugOnly(BOOL value)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_DEBUGONLY);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_DEBUGONLY,value);
+ return prevState;
+ }
+
+ void ResetDebugOnly()
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_DEBUGONLY);
+ }
+
+ #ifdef FEATURE_STACK_PROBE
+ //--//
+ BOOL IsSONotMainline()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_SONOTMAINLINE);
+ }
+
+ void SetSONotMainline()
+ {
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_SONOTMAINLINE);
+ }
+
+ BOOL SetSONotMainline(BOOL value)
+ {
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_SONOTMAINLINE);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_SONOTMAINLINE,value);
+ return prevState;
+ }
+
+ void ResetSONotMainline()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_SONOTMAINLINE);
+ }
+#endif
+
+ //--//
+ BOOL IsGetThreadAllowed()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_ALLOWGETTHREAD);
+
+ }
+ void SetGetThreadAllowed()
+ {
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_ALLOWGETTHREAD);
+ }
+
+
+ BOOL SetGetThreadAllowed(BOOL value)
+ {
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_ALLOWGETTHREAD);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_ALLOWGETTHREAD,value);
+ return prevState;
+ }
+
+ void ResetGetThreadAllowed()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_ALLOWGETTHREAD);
+ }
+
+ //--//
+ BOOL IsOkToLock()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_LOCK);
+ }
+
+ void SetOkToLock()
+ {
+ CONTRACT_BITMASK_SET(CONTRACT_BITMASK_OK_TO_LOCK);
+ }
+
+ BOOL SetOkToLock( BOOL value )
+ {
+ BOOL prevState = CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_LOCK);
+ CONTRACT_BITMASK_UPDATE(CONTRACT_BITMASK_OK_TO_LOCK, value);
+ return prevState;
+ }
+
+ void ResetOkToLock()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_OK_TO_LOCK);
+ }
+
+ //--//
+ BOOL IsOkToRetakeLock()
+ {
+ return CONTRACT_BITMASK_IS_SET(CONTRACT_BITMASK_OK_TO_RETAKE_LOCK);
+ }
+
+ void ResetOkToRetakeLock()
+ {
+ CONTRACT_BITMASK_RESET(CONTRACT_BITMASK_OK_TO_RETAKE_LOCK);
+ }
+
+
+ //--//
+ void LinkContractStackTrace( ContractStackRecord* pContractStackTrace )
+ {
+ pContractStackTrace->m_pNext = m_pContractStackTrace;
+
+ m_pContractStackTrace = pContractStackTrace;
+ }
+
+ ContractStackRecord* GetContractStackTrace()
+ {
+ return m_pContractStackTrace;
+ }
+
+ void SetContractStackTrace(ContractStackRecord* pContractStackTrace )
+ {
+ m_pContractStackTrace = pContractStackTrace;
+ }
+
+ //--//
+
+ UINT GetGCNoTriggerCount()
+ {
+ return m_GCNoTriggerCount;
+ }
+
+ void DecrementGCNoTriggerCount()
+ {
+ m_GCNoTriggerCount--;
+ }
+
+ void IncrementGCNoTriggerCount()
+ {
+ m_GCNoTriggerCount++;
+ }
+
+
+ UINT GetGCForbidCount()
+ {
+ return m_GCForbidCount;
+ }
+
+ void DecrementGCForbidCount()
+ {
+ m_GCForbidCount--;
+ }
+
+ void IncrementGCForbidCount()
+ {
+ m_GCForbidCount++;
+ }
+
+ UINT GetMaxLoadTypeLevel()
+ {
+ return m_maxLoadTypeLevel;
+ }
+
+ void SetMaxLoadTypeLevel(UINT newLevel)
+ {
+ m_maxLoadTypeLevel = newLevel;
+ }
+
+ //--//
+
+ void SetDbgStateLockData(DbgStateLockData * pDbgStateLockData)
+ {
+ m_LockState.SetDbgStateLockData(pDbgStateLockData);
+ }
+
+ DbgStateLockData * GetDbgStateLockData()
+ {
+ return m_LockState.GetDbgStateLockData();
+ }
+
+ void OnEnterCannotRetakeLockFunction()
+ {
+ m_LockState.OnEnterCannotRetakeLockFunction();
+ }
+
+#ifdef FEATURE_STACK_PROBE //SO contract functions only required when SO infrastructure is enabled
+ BOOL IsSOIntolerant()
+ {
+ return !IsSOTolerant();
+ }
+
+ BOOL BeginSOTolerant()
+ {
+ return SetSOTolerance(TRUE);
+ }
+
+ BOOL BeginSOIntolerant()
+ {
+ return SetSOTolerance(FALSE);
+ }
+
+
+ void CheckIfSOIntolerantOK(const char *szFunction, const char *szFile, int lineNum);
+
+
+
+
+
+ //--//
+
+ StackMarkerStack& GetStackMarkerStack()
+ {
+ return m_StackMarkerStack;
+ }
+#endif
+
+ void CheckOkayToLock(__in_z const char *szFunction, __in_z const char *szFile, int lineNum); // Asserts if its not okay to lock
+ BOOL CheckOkayToLockNoAssert(); // Returns if OK to lock
+ void LockTaken(DbgStateLockType dbgStateLockType,
+ UINT cEntrances,
+ void * pvLock,
+ __in_z const char * szFunction,
+ __in_z const char * szFile,
+ int lineNum);
+ void LockReleased(DbgStateLockType dbgStateLockType, UINT cExits, void * pvLock);
+ UINT GetLockCount(DbgStateLockType dbgStateLockType);
+ UINT GetCombinedLockCount();
+};
+
+#endif // ENABLE_CONTRACTS
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// Create ClrDebugState.
+// This routine is not allowed to return NULL. If it can't allocate the memory needed,
+// it should return a pointer to a global static ClrDebugState that indicates
+// that debug assertions should be skipped.
+ClrDebugState *CLRInitDebugState();
+ClrDebugState *GetClrDebugState(BOOL fAlloc = TRUE);
+
+
+// This function returns a ClrDebugState if one has been created, but will not create one itself.
+inline ClrDebugState *CheckClrDebugState()
+{
+ STATIC_CONTRACT_LIMITED_METHOD;
+ STATIC_CONTRACT_SO_TOLERANT;
+ ClrDebugState *ret = (ClrDebugState*)ClrFlsGetValue(TlsIdx_ClrDebugState);
+ return ret;
+}
+
+void CONTRACT_ASSERT(const char *szElaboration,
+ UINT whichTest,
+ UINT whichTestMask,
+ const char *szFunction,
+ const char *szFile,
+ int lineNum
+ );
+
+#endif
+
+// This needs to be defined up here b/c it is used by ASSERT_CHECK which is used by the contract impl
+#ifdef _DEBUG
+#ifdef ENTER_DEBUG_ONLY_CODE
+#undef ENTER_DEBUG_ONLY_CODE
+#endif
+#ifdef LEAVE_DEBUG_ONLY_CODE
+#undef LEAVE_DEBUG_ONLY_CODE
+#endif
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// This can only appear in a debug function so don't define it non-debug
+class DebugOnlyCodeHolder
+{
+public:
+ // We use GetClrDebugState on entry, but CheckClrDebugState on Leave
+ // That way we make sure to create one if we need to set state, but
+ // we don't recreated one on exit if its been deleted.
+ DEBUG_NOINLINE void Enter()
+ {
+ SCAN_SCOPE_BEGIN;
+ STATIC_CONTRACT_DEBUG_ONLY;
+
+ m_pClrDebugState = GetClrDebugState();
+ if (m_pClrDebugState)
+ {
+ m_oldDebugOnlyValue = m_pClrDebugState->IsDebugOnly();
+ m_pClrDebugState->SetDebugOnly();
+ }
+ }
+
+ DEBUG_NOINLINE void Leave()
+ {
+ SCAN_SCOPE_END;
+ STATIC_CONTRACT_DEBUG_ONLY;
+
+ m_pClrDebugState = CheckClrDebugState();
+ if (m_pClrDebugState)
+ {
+ m_pClrDebugState->SetDebugOnly( m_oldDebugOnlyValue );
+ }
+ }
+
+private:
+BOOL m_oldDebugOnlyValue;
+ClrDebugState *m_pClrDebugState;
+};
+
+#define ENTER_DEBUG_ONLY_CODE \
+ DebugOnlyCodeHolder __debugOnlyCodeHolder; \
+ __debugOnlyCodeHolder.Enter();
+
+#define LEAVE_DEBUG_ONLY_CODE \
+ __debugOnlyCodeHolder.Leave();
+
+
+class AutoCleanupDebugOnlyCodeHolder : public DebugOnlyCodeHolder
+{
+public:
+ DEBUG_NOINLINE AutoCleanupDebugOnlyCodeHolder()
+ {
+ SCAN_SCOPE_BEGIN;
+ STATIC_CONTRACT_DEBUG_ONLY;
+
+ Enter();
+ };
+
+ DEBUG_NOINLINE ~AutoCleanupDebugOnlyCodeHolder()
+ {
+ SCAN_SCOPE_END;
+
+ Leave();
+ };
+};
+
+#define DEBUG_ONLY_FUNCTION \
+ STATIC_CONTRACT_DEBUG_ONLY; \
+ AutoCleanupDebugOnlyCodeHolder __debugOnlyCodeHolder;
+
+#define DEBUG_ONLY_REGION() \
+ AutoCleanupDebugOnlyCodeHolder __debugOnlyCodeHolder;
+
+
+#define BEGIN_DEBUG_ONLY_CODE \
+ { \
+ AutoCleanupDebugOnlyCodeHolder __debugOnlyCodeHolder;
+
+#define END_DEBUG_ONLY_CODE \
+ }
+
+#else // ENABLE_CONTRACTS_IMPL
+#define DEBUG_ONLY_FUNCTION STATIC_CONTRACT_DEBUG_ONLY
+#define DEBUG_ONLY_REGION()
+#define BEGIN_DEBUG_ONLY_CODE
+#define END_DEBUG_ONLY_CODE
+#define ENTER_DEBUG_ONLY_CODE
+#define LEAVE_DEBUG_ONLY_CODE
+#endif
+
+#else // _DEBUG
+#define DEBUG_ONLY_REGION()
+#endif
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+// These helpers encapsulate our access to our FLS debug state. To improve
+// contract perf, we'll soon move these to a private alloced block
+// so we can reuse the pointer instead of constantly refetching it.
+// Thus, these helpers are just to bridge this transition.
+inline LPVOID GetViolationMask()
+{
+ ClrDebugState *pState = CheckClrDebugState();
+ if (pState)
+ {
+ return (LPVOID)pState->ViolationMask();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// This is the default binding of the MAYBETEMPLATE identifier,
+// used in the RETURN macro
+template <int DUMMY>
+class ___maybetemplate
+{
+ public:
+ FORCEINLINE void *operator new (size_t size)
+ {
+ return NULL;
+ }
+};
+
+// This is an abstract base class for contracts. The main reason we have this is so that the dtor for many derived class can
+// be performant. If this class was not abstract and had a dtor, then the dtor for the derived class adds EH overhead (even if the derived
+// class did not anything special in its dtor)
+class BaseContract
+{
+ // Really private, but used by macros
+ public:
+
+ // We use a single integer to specify all the settings for intrinsic tests
+ // such as THROWS and GC_TRIGGERS. The compiler should be able to fold all
+ // these clauses into a single constant.
+ //
+ // The value "0" is significant as this is what the entire mask will be initialized to
+ // in the absence of any clauses. Hence, whichever value is assigned "0" will be the
+ // default setting for the test.
+ //
+ // Also, there must be a "disabled" setting for each category in order to support
+ // the DISABLED macro.
+ enum TestEnum
+ {
+ THROWS_Mask = 0x00000003,
+ THROWS_Yes = 0x00000000, // the default
+ THROWS_No = 0x00000001,
+ THROWS_Disabled = 0x00000002,
+
+ GC_Mask = 0x0000000C,
+ GC_Triggers = 0x00000000, // the default
+ GC_NoTrigger = 0x00000004,
+ GC_Disabled = 0x00000008,
+
+ FAULT_Mask = 0x00000030,
+ FAULT_Disabled = 0x00000000, // the default
+ FAULT_Inject = 0x00000010,
+ FAULT_Forbid = 0x00000020,
+
+ MODE_Mask = 0x000000C0,
+ MODE_Disabled = 0x00000000, // the default
+ MODE_Preempt = 0x00000040,
+ MODE_Coop = 0x00000080,
+
+ // The following are used to assert the type of global state update being done by the function.
+ // This is used by the SO infrastructure to detect if we are probing properly. A CLR process will
+ // run in one of two states: SO-tolerant or SO-intolerant. In SO-tolerant mode, an SO is OK and we
+ // will not corrupt any global state. However, we cannot allow an SO to occur in SO-intolerant code
+ // because we might end up with our global state being corrupted.
+ //
+ // When we enter the EE from any entry point, we will begin in SO-tolerant mode and must probe for sufficient
+ // stack before entering SO-intolerant code. We will tell the differnce between SO-tolerant and SO-intolerant code
+ // by contract annotations on that function: SO_TOLERANT and SO_INTOLERANT.
+
+ // We enter the EE in SO_TOLERANT mode. All entry point functions into the EE must be marked as SO_TOLERANT and
+ // and must probe before calling an SO-intolerant function. We have a static analsysis tool that ensures that every
+ // entry point is tagged as SO_TOLERANT and that it probes before calling an SO_TOLERANT function.
+
+ // By default, all unannotated functions in the EE are SO_INTOLERANT which means that they must run behind a probe.
+ // Our contract checking will verify this at runtime. We only need to annotate a function explicilty as SO_INTOLERANT
+ // to tell our static analysis tool that they are not entry points (if it can't find a caller for a function, it assumes that the
+ // function is an entry point and should be marked SO_INTOLERANT.)
+
+ SO_TOLERANCE_Mask = 0x00000300,
+ SO_TOLERANT_No = 0x00000000, // the default.
+ SO_TOLERANT_Yes = 0x00000100,
+ SO_TOLERANCE_Disabled = 0x00000200,
+
+ DEBUG_ONLY_Yes = 0x00000400, // code runs under debug only
+
+ SO_MAINLINE_No = 0x00000800, // code is not part of our mainline SO scenario
+
+ // Any place where we can't safely call into the host should have a HOST_NoCalls contract
+ HOST_Mask = 0x00003000,
+ HOST_Calls = 0x00002000,
+ HOST_NoCalls = 0x00001000,
+ HOST_Disabled = 0x00000000, // the default
+
+ // This enforces the EE_THREAD_NOT_REQUIRED contract by clearing
+ // ClrDebugState::m_allowGetThread in its scope. That causes raw calls
+ // to GetThread() to assert, unless inside a temporary "don't worry it's ok" scope
+ // via BEGIN/END_GETTHREAD_ALLOWED. Useful for enforcing our docs that
+ // state certain unmanaged API entrypoints (e.g., some from profiling API)
+ // are callable without an EE Thread in TLS.
+ EE_THREAD_Mask = 0x0000C000,
+ EE_THREAD_Disabled = 0x00000000, // the default
+ EE_THREAD_Required = 0x00004000,
+ EE_THREAD_Not_Required = 0x00008000,
+
+ // These enforce the CAN_TAKE_LOCK / CANNOT_TAKE_LOCK contracts
+ CAN_TAKE_LOCK_Mask = 0x00060000,
+ CAN_TAKE_LOCK_Yes = 0x00020000,
+ CAN_TAKE_LOCK_No = 0x00040000,
+ CAN_TAKE_LOCK_Disabled = 0x00000000, // the default
+
+ // These enforce the CANNOT_RETAKE_LOCK contract
+ CAN_RETAKE_LOCK_No = 0x00080000,
+ CAN_RETAKE_LOCK_No_Disabled = 0x00000000, // the default
+
+ PRECONDITION_Used = 0x00010000, // a PRECONDITION appeared inside the contract
+
+ // IMPORTANT!!! LOADS_TYPE_Mask and LOADS_TYPE_Shift must be kept in sync.
+ LOADS_TYPE_Mask = 0x00f00000, // the max loadstype level + 1 ("+1" because 0 is reserved for the default which is "disabled")
+ LOADS_TYPE_Shift = 20, // # of bits to right-shift to get loadstype bits to rightmost position.
+ LOADS_TYPE_Disabled = 0x00000000, // the default
+
+ ALL_Disabled = THROWS_Disabled|GC_Disabled|FAULT_Disabled|MODE_Disabled|LOADS_TYPE_Disabled|
+ SO_TOLERANCE_Disabled|HOST_Disabled|EE_THREAD_Disabled|CAN_TAKE_LOCK_Disabled|CAN_RETAKE_LOCK_No_Disabled
+
+ };
+
+ enum Operation
+ {
+ Setup = 0x01,
+ Preconditions = 0x02,
+ Postconditions = 0x04,
+ };
+
+
+ __declspec(nothrow) BaseContract() : m_pClrDebugState(NULL), m_testmask(0)
+ {
+ }
+ __declspec(nothrow) void Restore()
+ {
+ // m_pClrDebugState is setup in BaseContract::DoChecks. If an SO happens after the
+ // BaseContract object is constructed but before DoChecks is invoked, m_pClrDebugState
+ // will remain NULL (which is what it is set to in the BaseContract ctor).
+ //
+ // Thus, we should check for it being NULL before dereferencing it.
+ if (m_pClrDebugState)
+ {
+ // Backout all changes to debug state.
+ *m_pClrDebugState = m_IncomingClrDebugState;
+ }
+ }
+
+ void DoChecks(UINT testmask, __in_z const char *szFunction, __in_z char *szFile, int lineNum);
+ void Disable()
+ {
+ }
+ BOOL CheckFaultInjection();
+
+ protected:
+ UINT m_testmask;
+ // Override this function in any derived class to indicate that you have defined a destructor for that class
+ // and that dtor calls Restore()
+ virtual void DestructorDefinedThatCallsRestore() = 0;
+
+
+ protected:
+ ClrDebugState *m_pClrDebugState;
+ ClrDebugState m_IncomingClrDebugState;
+
+ ContractStackRecord m_contractStackRecord;
+
+ public:
+ // --------------------------------------------------------------------------------
+ // These classes and declarations are used to implement our fake return keyword.
+ // --------------------------------------------------------------------------------
+
+ // ___box is used to protect the "detected" return value from being combined with other parts
+ // of the return expression after we have processed it. This can happen if the return
+ // expression is a non-parenthesized expression with an operator of lower precedence than
+ // ">".
+ //
+ // If you have such a case (and see this class listed in an error message),
+ // parenthesize your return value expression.
+ template <typename T>
+ class Box__USE_PARENS_WITH_THIS_EXPRESSION
+ {
+ const T &value;
+
+ public:
+
+ FORCEINLINE Box__USE_PARENS_WITH_THIS_EXPRESSION(const T &value)
+ : value(value)
+ {
+ }
+
+ FORCEINLINE const T& Unbox()
+ {
+ return value;
+ }
+ };
+
+ // PseudoTemplate is a class which can be instantated with a template-like syntax, resulting
+ // in an expression which simply boxes a following value in a Box
+
+ template <typename T>
+ class PseudoTemplate
+ {
+ public:
+ FORCEINLINE void *operator new (size_t size)
+ {
+ return NULL;
+ }
+
+ FORCEINLINE Box__USE_PARENS_WITH_THIS_EXPRESSION<T> operator>(const T &value)
+ {
+ return Box__USE_PARENS_WITH_THIS_EXPRESSION<T>(value);
+ }
+
+ FORCEINLINE PseudoTemplate operator<(int dummy)
+ {
+ return PseudoTemplate();
+ }
+ };
+
+ // Returner is used to assign the return value to the RETVAL local. Note the use of
+ // operator , because of its low precedence.
+
+ template <typename RETURNTYPE>
+ class Returner
+ {
+ RETURNTYPE &m_value;
+ BOOL m_got;
+ public:
+
+ FORCEINLINE Returner(RETURNTYPE &value)
+ : m_value(value),
+ m_got(FALSE)
+ {
+ }
+
+ template <typename T>
+ FORCEINLINE RETURNTYPE operator,(Box__USE_PARENS_WITH_THIS_EXPRESSION<T> value)
+ {
+ m_value = value.Unbox();
+ m_got = TRUE;
+ return m_value;
+ }
+
+ FORCEINLINE void operator,(___maybetemplate<0> &dummy)
+ {
+ m_got = TRUE;
+ }
+
+ FORCEINLINE BOOL GotReturn()
+ {
+ return m_got;
+ }
+ };
+
+ // This type ensures that postconditions were run via RETURN or RETURN_VOID
+ class RanPostconditions
+ {
+ public:
+ bool ran;
+ int count;
+ const char *function;
+
+ FORCEINLINE RanPostconditions(const char *function)
+ : ran(false),
+ count(0),
+ function(function)
+ {
+ }
+
+ FORCEINLINE int operator++()
+ {
+ return ++count;
+ }
+
+ FORCEINLINE ~RanPostconditions()
+ {
+ // Note: __uncaught_exception() is not a perfect check. It will return TRUE during any exception
+ // processing. So, if there is a contract called from an exception filter (like our
+ // COMPlusFrameHandler) then it will return TRUE and the saftey check below will not be performed.
+ if (!__uncaught_exception())
+ ASSERT_CHECK(count == 0 || ran, function, "Didn't run postconditions - be sure to use RETURN at the end of the function");
+ }
+
+ };
+
+ // Set contract enforcement level
+ static void SetUnconditionalContractEnforcement(BOOL enforceUnconditionally);
+
+ // Check contract enforcement
+ static BOOL EnforceContract();
+
+ private:
+ static BOOL s_alwaysEnforceContracts;
+};
+
+class Contract: public BaseContract
+{
+ // Have to override this function in any derived class to indicate that a valid destructor is defined for this class
+ virtual void DestructorDefinedThatCallsRestore(){}
+
+ public:
+ __declspec(nothrow) ~Contract()
+ {
+ Restore();
+ }
+};
+
+#endif // ENABLE_CONTRACTS_IMPL
+
+
+#ifdef _DEBUG
+
+// Valid parameters for CONTRACT_VIOLATION macro
+enum ContractViolationBits
+{
+ ThrowsViolation = 0x00000001, // suppress THROW tags in this scope
+ GCViolation = 0x00000002, // suppress GCTRIGGER tags in this scope
+ ModeViolation = 0x00000004, // suppress MODE_PREEMP and MODE_COOP tags in this scope
+ FaultViolation = 0x00000008, // suppress INJECT_FAULT assertions in this scope
+ FaultNotFatal = 0x00000010, // suppress INJECT_FAULT but not fault injection by harness
+ SOToleranceViolation = 0x00000020, // suppress SO_TOLERANCE tags in this scope
+ LoadsTypeViolation = 0x00000040, // suppress LOADS_TYPE tags in this scope
+ TakesLockViolation = 0x00000080, // suppress CAN_TAKE_LOCK tags in this scope
+ HostViolation = 0x00000100, // suppress HOST_CALLS tags in this scope
+ EEThreadViolation = 0x00000200, // suppress EE_THREAD_REQUIRED tags in this scope
+
+ //These are not violation bits. We steal some bits out of the violation mask to serve as
+ // general flag bits.
+ CanFreeMe = 0x00010000, // If this bit is ON, the ClrDebugState was allocated by
+ // a version of utilcode that registers an Fls Callback to free
+ // the state. If this bit is OFF, the ClrDebugState was allocated
+ // by an old version of utilcode that doesn't. (And you can't
+ // assume that the old utilcode used the same allocator as the new utilcode.)
+ // (Most likely, this is because you are using an older shim with
+ // a newer mscorwks.dll)
+ //
+ // The Fls callback must only attempt to free debugstates that
+ // have this bit on.
+
+ BadDebugState = 0x00020000, // If we OOM creating the ClrDebugState, we return a pointer to
+ // a static ClrDebugState that has this bit turned on. (We don't
+ // want to slow down contracts with null tests everywhere.)
+ // Other than this specific bit, all other fields of the DebugState
+ // must be considered trash. You can stomp on them and you can bit-test them
+ // but you can't throw up any asserts based on them and you certainly
+ // can't deref any pointers stored in the bad DebugState.
+
+ AllViolation = 0xFFFFFFFF,
+};
+
+#endif
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+// Global variables allow PRECONDITION and POSTCONDITION to be used outside contracts
+static const BaseContract::Operation ___op = (Contract::Operation) (Contract::Preconditions
+ |Contract::Postconditions);
+enum {
+ ___disabled = 0
+};
+
+static UINT ___testmask;
+
+// End of global variables
+
+static int ___ran;
+
+class __SafeToUsePostCondition {
+public:
+ static int safe_to_use_postcondition() {return 0;};
+};
+
+class __YouCannotUseAPostConditionHere {
+private:
+ static int safe_to_use_postcondition() {return 0;};
+};
+
+typedef __SafeToUsePostCondition __PostConditionOK;
+
+// Uncomment the following line to disable runtime contracts completely - PRE/POST conditions will still be present
+//#define __FORCE_NORUNTIME_CONTRACTS__ 1
+
+#ifndef __FORCE_NORUNTIME_CONTRACTS__
+
+#define CONTRACT_SETUP(_contracttype, _returntype, _returnexp) \
+ _returntype RETVAL; \
+ _contracttype ___contract; \
+ Contract::Returner<_returntype> ___returner(RETVAL); \
+ Contract::RanPostconditions ___ran(__FUNCTION__); \
+ Contract::Operation ___op = Contract::Setup; \
+ DEBUG_ASSURE_NO_RETURN_BEGIN(CONTRACT) \
+ BOOL ___contract_enabled = Contract::EnforceContract(); \
+ enum {___disabled = 0}; \
+ if (!___contract_enabled) \
+ ___contract.Disable(); \
+ else \
+ { \
+ enum { ___CheckMustBeInside_CONTRACT = 1 }; \
+ if (0) \
+ { \
+ /* If you see an "unreferenced label" warning with this name, */\
+ /* Be sure that you have a RETURN at the end of your */ \
+ /* CONTRACT_VOID function */ \
+ ___run_postconditions_DID_YOU_FORGET_A_RETURN: \
+ if (___contract_enabled) \
+ { \
+ ___op = Contract::Postconditions; \
+ ___ran.ran = true; \
+ } \
+ else \
+ { \
+ DEBUG_OK_TO_RETURN_BEGIN(CONTRACT) \
+ ___run_return: \
+ return _returnexp; \
+ DEBUG_OK_TO_RETURN_END(CONTRACT) \
+ } \
+ } \
+ if (0) \
+ { \
+ ___run_preconditions: \
+ ___op = Contract::Preconditions; \
+ } \
+ UINT ___testmask = 0; \
+
+#define CONTRACTL_SETUP(_contracttype) \
+ _contracttype ___contract; \
+ BOOL ___contract_enabled = Contract::EnforceContract(); \
+ enum {___disabled = 0}; \
+ if (!___contract_enabled) \
+ ___contract.Disable(); \
+ else \
+ { \
+ typedef __YouCannotUseAPostConditionHere __PostConditionOK; \
+ enum { ___CheckMustBeInside_CONTRACT = 1 }; \
+ Contract::Operation ___op = Contract::Setup; \
+ enum {___disabled = 0}; \
+ if (0) \
+ { \
+ ___run_preconditions: \
+ ___op = Contract::Preconditions; \
+ } \
+ if (0) \
+ { \
+ /* define for CONTRACT_END even though we can't get here */ \
+ ___run_return: \
+ UNREACHABLE(); \
+ } \
+ UINT ___testmask = 0; \
+
+#else // #ifndef __FORCE_NORUNTIME_CONTRACTS__
+
+#define CONTRACT_SETUP(_contracttype, _returntype, _returnexp) \
+ _returntype RETVAL; \
+ Contract::Returner<_returntype> ___returner(RETVAL); \
+ Contract::RanPostconditions ___ran(__FUNCTION__); \
+ Contract::Operation ___op = Contract::Setup; \
+ DEBUG_ASSURE_NO_RETURN_BEGIN(CONTRACT) \
+ BOOL ___contract_enabled = Contract::EnforceContract(); \
+ enum {___disabled = 0}; \
+ { \
+ enum { ___CheckMustBeInside_CONTRACT = 1 }; \
+ if (0) \
+ { \
+ /* If you see an "unreferenced label" warning with this name, */\
+ /* Be sure that you have a RETURN at the end of your */ \
+ /* CONTRACT_VOID function */ \
+ ___run_postconditions_DID_YOU_FORGET_A_RETURN: \
+ if (___contract_enabled) \
+ { \
+ ___op = Contract::Postconditions; \
+ ___ran.ran = true; \
+ } \
+ else \
+ { \
+ DEBUG_OK_TO_RETURN_BEGIN(CONTRACT) \
+ ___run_return: \
+ return _returnexp; \
+ DEBUG_OK_TO_RETURN_END(CONTRACT) \
+ } \
+ } \
+ if (0) \
+ { \
+ ___run_preconditions: \
+ ___op = Contract::Preconditions; \
+ } \
+ UINT ___testmask = 0; \
+
+
+
+
+#define CONTRACTL_SETUP(_contracttype) \
+ BOOL ___contract_enabled = Contract::EnforceContract(); \
+ enum {___disabled = 0}; \
+ { \
+ typedef __YouCannotUseAPostConditionHere __PostConditionOK; \
+ enum { ___CheckMustBeInside_CONTRACT = 1 }; \
+ Contract::Operation ___op = Contract::Setup; \
+ enum {___disabled = 0}; \
+ if (0) \
+ { \
+ ___run_preconditions: \
+ ___op = Contract::Preconditions; \
+ } \
+ if (0) \
+ { \
+ /* define for CONTRACT_END even though we can't get here */ \
+ ___run_return: \
+ UNREACHABLE(); \
+ } \
+ UINT ___testmask = 0; \
+
+#endif // __FORCE_NORUNTIME_CONTRACTS__
+
+
+#define CUSTOM_CONTRACT(_contracttype, _returntype) \
+ typedef Contract::PseudoTemplate<_returntype> ___maybetemplate; \
+ CONTRACT_SETUP(_contracttype, _returntype, RETVAL)
+
+#define CUSTOM_CONTRACT_VOID(_contracttype) \
+ CONTRACT_SETUP(_contracttype, int, ;)
+
+#define CUSTOM_CONTRACTL(_contracttype) \
+ CONTRACTL_SETUP(_contracttype)
+
+// Although this thing only needs to run in the Setup phase, we'll let it
+// run unconditionally. This way, the compiler will see a sequence like this:
+//
+// THROWS; GC_TRIGGERS; FORBID_FAULT ==>
+//
+// ___testmask |= constant
+// ___testmask |= constant
+// ___testmask |= constant
+//
+// and be able to fold all these into a single constant at runtime.
+//
+#define REQUEST_TEST(thetest, todisable) (___testmask |= (___CheckMustBeInside_CONTRACT, (___disabled ? (todisable) : (thetest))))
+
+
+#define INJECT_FAULT(_statement) \
+ do \
+ { \
+ STATIC_CONTRACT_FAULT; \
+ REQUEST_TEST(Contract::FAULT_Inject, Contract::FAULT_Disabled); \
+ if (0) \
+ { \
+ _statement; \
+ } \
+ } \
+ while(0) \
+
+
+#define FORBID_FAULT do { STATIC_CONTRACT_FORBID_FAULT; REQUEST_TEST(Contract::FAULT_Forbid, Contract::FAULT_Disabled); } while(0)
+
+#define THROWS do { STATIC_CONTRACT_THROWS; REQUEST_TEST(Contract::THROWS_Yes, Contract::THROWS_Disabled); } while(0)
+
+#define NOTHROW do { STATIC_CONTRACT_NOTHROW; REQUEST_TEST(Contract::THROWS_No, Contract::THROWS_Disabled); } while(0) \
+
+#define ENTRY_POINT do { STATIC_CONTRACT_ENTRY_POINT; REQUEST_TEST(Contract::SO_TOLERANT_Yes, Contract::SO_TOLERANCE_Disabled); } while(0)
+
+#define LOADS_TYPE(maxlevel) do { REQUEST_TEST( ((maxlevel) + 1) << Contract::LOADS_TYPE_Shift, Contract::LOADS_TYPE_Disabled ); } while(0)
+
+#define SO_TOLERANT do { STATIC_CONTRACT_SO_TOLERANT; REQUEST_TEST(Contract::SO_TOLERANT_Yes, Contract::SO_TOLERANCE_Disabled); } while(0)
+
+#define SO_INTOLERANT do { STATIC_CONTRACT_SO_INTOLERANT; REQUEST_TEST(Contract::SO_TOLERANT_No, Contract::SO_TOLERANCE_Disabled); } while(0)
+
+#define SO_NOT_MAINLINE do { STATIC_CONTRACT_SO_NOT_MAINLINE; REQUEST_TEST(Contract::SO_MAINLINE_No, 0); } while (0)
+
+#define CAN_TAKE_LOCK do { STATIC_CONTRACT_CAN_TAKE_LOCK; REQUEST_TEST(Contract::CAN_TAKE_LOCK_Yes, Contract::CAN_TAKE_LOCK_Disabled); } while(0)
+
+#define CANNOT_TAKE_LOCK do { STATIC_CONTRACT_CANNOT_TAKE_LOCK; REQUEST_TEST(Contract::CAN_TAKE_LOCK_No, Contract::CAN_TAKE_LOCK_Disabled); } while(0)
+
+#define CANNOT_RETAKE_LOCK do { REQUEST_TEST(Contract::CAN_RETAKE_LOCK_No, Contract::CAN_RETAKE_LOCK_No_Disabled); } while(0)
+
+#define DEBUG_ONLY do { STATIC_CONTRACT_DEBUG_ONLY; REQUEST_TEST(Contract::DEBUG_ONLY_Yes, 0); } while (0)
+
+#ifndef __DISABLE_PREPOST_CONDITIONS__
+#define PRECONDITION_MSG(_expression, _message) \
+ do \
+ { \
+ enum { ___CheckMustBeInside_CONTRACT = 1 }; \
+ REQUEST_TEST(Contract::PRECONDITION_Used, 0); \
+ if ((___op&Contract::Preconditions) && !___disabled) \
+ ASSERT_CHECK(_expression, _message, "Precondition failure"); \
+ } \
+ while(0)
+
+
+#define PRECONDITION(_expression) \
+ PRECONDITION_MSG(_expression, NULL)
+
+#define POSTCONDITION_MSG(_expression, _message) \
+ ++___ran; \
+ if ((!(0 && __PostConditionOK::safe_to_use_postcondition())) && \
+ (___op&Contract::Postconditions) && \
+ !___disabled) \
+ { \
+ ASSERT_CHECK(_expression, _message, "Postcondition failure"); \
+ }
+
+#define POSTCONDITION(_expression) \
+ POSTCONDITION_MSG(_expression, NULL)
+
+#define INSTANCE_CHECK \
+ ___CheckMustBeInside_CONTRACT; \
+ if ((___op&Contract::Preconditions) && !___disabled) \
+ ASSERT_CHECK(CheckPointer(this), NULL, "Instance precheck failure"); \
+ ++___ran; \
+ if ((___op&Contract::Postconditions) && !___disabled) \
+ ASSERT_CHECK(CheckPointer(this), NULL, "Instance postcheck failure");
+
+#define INSTANCE_CHECK_NULL \
+ ___CheckMustBeInside_CONTRACT; \
+ if ((___op&Contract::Preconditions) && !___disabled) \
+ ASSERT_CHECK(CheckPointer(this, NULL_OK), NULL, "Instance precheck failure"); \
+ ++___ran; \
+ if ((___op&Contract::Postconditions) && !___disabled) \
+ ASSERT_CHECK(CheckPointer(this, NULL_OK), NULL, "Instance postcheck failure");
+
+#define CONSTRUCTOR_CHECK \
+ ___CheckMustBeInside_CONTRACT; \
+ ++___ran; \
+ if ((___op&Contract::Postconditions) && !___disabled) \
+ ASSERT_CHECK(CheckPointer(this), NULL, "Instance postcheck failure");
+
+#define DESTRUCTOR_CHECK \
+ ___CheckMustBeInside_CONTRACT; \
+ NOTHROW; \
+ if ((___op&Contract::Preconditions) && !___disabled) \
+ ASSERT_CHECK(CheckPointer(this), NULL, "Instance precheck failure");
+#else // __DISABLE_PREPOST_CONDITIONS__
+
+
+#define PRECONDITION_MSG(_expression, _message) do { } while(0)
+#define PRECONDITION(_expression) do { } while(0)
+#define POSTCONDITION_MSG(_expression, _message) do { } while(0)
+#define POSTCONDITION(_expression) do { } while(0)
+#define INSTANCE_CHECK
+#define INSTANCE_CHECK_NULL
+#define CONSTRUCTOR_CHECK
+#define DESTRUCTOR_CHECK
+
+#endif // __DISABLE_PREPOST_CONDITIONS__
+
+#define UNCHECKED(thecheck) \
+ do { \
+ ANNOTATION_UNCHECKED(thecheck); \
+ enum {___disabled = 1 }; \
+ thecheck; \
+ } while(0)
+
+#define DISABLED(thecheck) UNCHECKED(thecheck)
+
+#define WRAPPER(thecheck) UNCHECKED(thecheck)
+
+// This keyword is redundant but it's handy for reducing the nuisance editing you
+// have to when repeatedly enabling and disabling contract items while debugging.
+// You shouldn't check in code that explicitly uses ENABLED.
+#define ENABLED(_check) _check
+
+
+#ifndef __FORCE_NORUNTIME_CONTRACTS__
+#define CONTRACTL_END \
+ if (___op & Contract::Setup) \
+ { \
+ ___contract.DoChecks(___testmask, __FUNCTION__, __FILE__, __LINE__); \
+ if (___testmask & Contract::PRECONDITION_Used) \
+ { \
+ goto ___run_preconditions; \
+ } \
+ } \
+ else if (___op & Contract::Postconditions) \
+ { \
+ goto ___run_return; \
+ } \
+ ___CheckMustBeInside_CONTRACT; \
+ }
+
+#else
+
+#define CONTRACTL_END \
+ if (___op & Contract::Setup) \
+ { \
+ if (___testmask & Contract::PRECONDITION_Used) \
+ { \
+ goto ___run_preconditions; \
+ } \
+ } \
+ else if (___op & Contract::Postconditions) \
+ { \
+ goto ___run_return; \
+ } \
+ ___CheckMustBeInside_CONTRACT; \
+ } \
+
+#endif // __FORCE_NORUNTIME_CONTRACTS__
+
+#define CONTRACT_END CONTRACTL_END \
+ DEBUG_ASSURE_NO_RETURN_END(CONTRACT) \
+
+
+// The final expression in the RETURN macro deserves special explanation (or something.)
+// The expression is constructed so as to be syntactically ambiguous, depending on whether
+// __maybetemplate is a template or not. If it is a template, the expression is syntactically
+// correct as-is. If it is not, the angle brackets are interpreted as
+// less than & greater than, and the expression is incomplete. This is the point - we can
+// choose whether we need an expression or not based on the context in which the macro is used.
+// This allows the same RETURN macro to be used both in value-returning and void-returning
+// contracts.
+//
+// The "__returner ," portion of the expression is used instead of "RETVAL =", since ","
+// has lower precedence than "=". (Ain't overloaded operators fun.)
+//
+// Also note that the < and > operators on the non-template version of __maybetemplate
+// are overridden to "box" the return value in a special type and pass it
+// through to the __returner's "," operator. This is so we can detect a case where an
+// operator with lower precedence than ">" is in the return expression - in such a case we
+// will get a type error message, which instructs that parens be placed around the return
+// value expression.
+
+#define RETURN_BODY \
+ if (___returner.GotReturn()) \
+ goto ___run_postconditions_DID_YOU_FORGET_A_RETURN; \
+ else \
+ ___returner, * new ___maybetemplate < 0 >
+
+
+// We have two versions of the RETURN macro. CONTRACT_RETURN is for use inside the CONTRACT
+// scope where it is OK to return this way, even though the CONTRACT macro itself does not
+// allow a return. RETURN is for use inside the function body where it might not be OK
+// to return and we need to ensure that we don't allow a return where one should not happen
+//
+#define RETURN \
+ while (DEBUG_ASSURE_SAFE_TO_RETURN, TRUE) \
+ RETURN_BODY \
+
+#define RETURN_VOID \
+ RETURN
+
+#define CONTRACT_RETURN \
+ while (___CheckMustBeInside_CONTRACT, TRUE) \
+ RETURN_BODY \
+
+#define CONTRACT_RETURN_VOID \
+ CONTRACT_RETURN \
+
+#if 0
+#define CUSTOM_LIMITED_METHOD_CONTRACT(_contracttype) \
+ { \
+ _contracttype ___contract; \
+ STATIC_CONTRACT_LEAF; \
+ ___contract.DoChecks(Contract::THROWS_No|Contract::GC_NoTrigger|Contract::MODE_Disabled|Contract::FAULT_Disabled); \
+ /* Should add some assertion mechanism to ensure no other contracts are called */ \
+ }
+#else
+#define CUSTOM_LIMITED_METHOD_CONTRACT(_contracttype) \
+ { \
+ STATIC_CONTRACT_LEAF; \
+ }
+#endif
+
+#define CUSTOM_WRAPPER_NO_CONTRACT(_contracttype) \
+ { \
+ /* Should add some assertion mechanism to ensure one other contract is called */ \
+ STATIC_CONTRACT_WRAPPER; \
+ }
+
+#define CONTRACT_THROWS() \
+ { \
+ ::GetClrDebugState()->CheckOkayToThrow(__FUNCTION__, __FILE__, __LINE__); \
+ }
+
+#define CONTRACT_THROWSEX(__func, __file, __line) \
+ { \
+ ::GetClrDebugState()->CheckOkayToThrow(__func, __file, __line); \
+ }
+
+#else // ENABLE_CONTRACTS_IMPL
+#define CUSTOM_CONTRACT(_contracttype, _returntype) if (0) { struct YouCannotUseThisHere { int x; }; // This temporary typedef allows retail use of
+#define CUSTOM_CONTRACT_VOID(_contracttype) if (0) { struct YouCannotUseThisHere { int x; }; // FORBIDGC_LOADER_USE_ENABLED
+#define CUSTOM_CONTRACTL(_contracttype) if (0) { struct YouCannotUseThisHere { int x; }; // inside contracts and asserts but nowhere else.
+
+#define INJECT_FAULT(_statement)
+#define FORBID_FAULT
+#define THROWS
+#define NOTHROW
+#define CAN_TAKE_LOCK
+#define CANNOT_TAKE_LOCK
+#define CANNOT_RETAKE_LOCK
+#define LOADS_TYPE(maxlevel)
+#define SO_TOLERANT
+#define SO_INTOLERANT
+#define SO_NOT_MAINLINE
+#define ENTRY_POINT
+
+#ifdef _DEBUG
+// This can only appear in a debug function so don't define it non-debug
+#define DEBUG_ONLY STATIC_CONTRACT_DEBUG_ONLY
+#else
+#define DEBUG_ONLY
+#endif
+
+#define PRECONDITION_MSG(_expression, _message) do { } while(0)
+#define PRECONDITION(_expression) do { } while(0)
+#define POSTCONDITION_MSG(_expression, _message) do { } while(0)
+#define POSTCONDITION(_expression) do { } while(0)
+#define INSTANCE_CHECK
+#define INSTANCE_CHECK_NULL
+#define CONSTRUCTOR_CHECK
+#define DESTRUCTOR_CHECK
+#define UNCHECKED(thecheck)
+#define DISABLED(thecheck)
+#define WRAPPER(thecheck)
+#define ENABLED(_check)
+#define CONTRACT_END }
+#define CONTRACTL_END }
+
+#define CUSTOM_LIMITED_METHOD_CONTRACT(_contracttype) \
+ { \
+ /* Should add some assertion mechanism to ensure one other contract is called */ \
+ STATIC_CONTRACT_LEAF; \
+ }
+#define CUSTOM_WRAPPER_NO_CONTRACT(_contracttype) \
+ { \
+ /* Should add some assertion mechanism to ensure one other contract is called */ \
+ STATIC_CONTRACT_WRAPPER; \
+ }
+
+
+#define RETURN return
+#define RETURN_VOID RETURN
+
+#define CONTRACT_THROWS()
+#define CONTRACT_THROWSEX(__func, __file, __line)
+
+#endif // ENABLE_CONTRACTS_IMPL
+
+
+#define CONTRACT(_returntype) CUSTOM_CONTRACT(Contract, _returntype)
+#define CONTRACT_VOID CUSTOM_CONTRACT_VOID(Contract)
+#define CONTRACTL CUSTOM_CONTRACTL(Contract)
+
+// See description near the top of the file
+#define LIMITED_METHOD_CONTRACT CUSTOM_LIMITED_METHOD_CONTRACT(Contract)
+
+#define WRAPPER_NO_CONTRACT CUSTOM_WRAPPER_NO_CONTRACT(Contract)
+
+// GC_NOTRIGGER allowed but not currently enforced at runtime
+#define GC_NOTRIGGER STATIC_CONTRACT_GC_NOTRIGGER
+#define GC_TRIGGERS static_assert(false, "TriggersGC not supported in utilcode contracts")
+
+#ifdef ENABLE_CONTRACTS_IMPL
+template <UINT_PTR VIOLATION_MASK>
+class ContractViolationHolder
+{
+public:
+ ContractViolationHolder()
+ {
+ m_pviolationmask = NULL;
+ m_oldviolationmask = 0;
+ }
+
+ DEBUG_NOINLINE void Enter();
+
+ DEBUG_NOINLINE void Leave()
+ {
+ SCAN_SCOPE_END;
+ LeaveInternal();
+ };
+
+protected:
+ // We require that violationMask is passed as a parameter here to hopefully defeat the
+ // compiler's desire to fold all the Enter and Ctor implementations together.
+ FORCEINLINE void EnterInternal(UINT_PTR violationMask)
+ {
+ _ASSERTE(0 == (violationMask & ~(ThrowsViolation | GCViolation | ModeViolation | FaultViolation |
+ FaultNotFatal | SOToleranceViolation | HostViolation |
+ TakesLockViolation | LoadsTypeViolation)) ||
+ violationMask == AllViolation);
+
+ m_pviolationmask = GetClrDebugState()->ViolationMaskPtr();
+ m_oldviolationmask = *m_pviolationmask;
+ *m_pviolationmask = (m_oldviolationmask | violationMask);
+ };
+
+ FORCEINLINE void LeaveInternal()
+ {
+ // This can be used in places where our debug state has been destroyed, so check for it first.
+ if (CheckClrDebugState())
+ {
+ _ASSERTE(m_pviolationmask != NULL);
+ *m_pviolationmask = m_oldviolationmask;
+ }
+ };
+
+ UINT_PTR *m_pviolationmask;
+ UINT_PTR m_oldviolationmask;
+};
+
+template <UINT_PTR VIOLATION_MASK>
+class AutoCleanupContractViolationHolder : ContractViolationHolder<VIOLATION_MASK>
+{
+public:
+ DEBUG_NOINLINE AutoCleanupContractViolationHolder(BOOL fEnterViolation = TRUE);
+
+ DEBUG_NOINLINE ~AutoCleanupContractViolationHolder()
+ {
+ SCAN_SCOPE_END;
+ LeaveInternal();
+ };
+};
+
+#endif // ENABLE_CONTRACTS_IMPL
+
+#ifdef ENABLE_CONTRACTS_IMPL
+#define BEGIN_CONTRACT_VIOLATION(violationmask) \
+ { \
+ ContractViolationHolder<violationmask> __violationHolder_onlyOneAllowedPerScope; \
+ __violationHolder_onlyOneAllowedPerScope.Enter(); \
+ DEBUG_ASSURE_NO_RETURN_BEGIN(CONTRACT) \
+
+// Use this to jump out prematurely from a violation. Used for EH
+// when the function might not return
+#define RESET_CONTRACT_VIOLATION() \
+ __violationHolder_onlyOneAllowedPerScope.Leave(); \
+
+#define END_CONTRACT_VIOLATION \
+ DEBUG_ASSURE_NO_RETURN_END(CONTRACT) \
+ __violationHolder_onlyOneAllowedPerScope.Leave(); \
+ } \
+
+// See description near the top of the file
+#define CONTRACT_VIOLATION(violationMask) \
+ AutoCleanupContractViolationHolder<violationMask> __violationHolder_onlyOneAllowedPerScope;
+
+
+// Reasons for having the violation. Use one of these values as an additional parameter to
+// E.g. PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonContractInfrastructure)
+// New values and explanations can be added when needed.
+enum PermanentContractViolationReason
+{
+ ReasonContractInfrastructure, // This violation is there for contract test or infrastructure purposes.
+ ReasonDebugOnly, // Code path doesn't occur on retail builds
+ ReasonNonShippingCode, // Code runs in undocumented non-shipping feature
+ ReasonIBC, // Code runs in IBC scenarios only and the violation is safe.
+ ReasonNGEN, // Code runs in NGEN scenarios only and the violation is safe.
+ ReasonProfilerCallout, // Profiler implementers are guaranteed not to throw.
+ ReasonUnsupportedForSQLF1Profiling, // This code path violates HOST_NOCALLS, but that's ok b/c SQL will never
+ // invoke it, and thus SQL/F1 profiling (the primary reason to enforce
+ // HOST_NOCALLS) is not in danger.
+ ReasonRuntimeReentrancy, // e.g. SafeQueryInterface
+ ReasonShutdownOnly, // Code path only runs as part of Shutdown and the violation is safe.
+ ReasonSOTolerance, // We would like to redesign SO contracts anyways
+ ReasonStartupOnly, // Code path only runs as part of Startup and the violation is safe.
+ ReasonWorkaroundForScanBug, // Violation is needed because of a bug in SCAN
+ ReasonProfilerAsyncCannotRetakeLock, // Profiler may call this from redirected thread, causing a CANNOT_TAKE_LOCK
+ // violation, but the scope is still protected with CANNOT_RETAKE_LOCK
+ ReasonILStubWillNotThrow, // Specially-crafted reverse COM IL stubs will not throw
+};
+
+// See the discussion near the top of the file on the use of PERMANENT_CONTRACT_VIOLATION
+// The reasonEnum is currently only used for documentation and searchability. Here
+// we have the compiler check for a typo.
+#define PERMANENT_CONTRACT_VIOLATION(violationMask, reasonEnum) \
+ if (0) \
+ PermanentContractViolationReason reason = reasonEnum; \
+ CONTRACT_VIOLATION(violationMask)
+
+#define CONDITIONAL_CONTRACT_VIOLATION(violationMask, condition) \
+ AutoCleanupContractViolationHolder<violationMask> __violationHolder_onlyOneAllowedPerScope((condition));
+
+#else
+#define BEGIN_CONTRACT_VIOLATION(violationmask)
+#define RESET_CONTRACT_VIOLATION()
+#define END_CONTRACT_VIOLATION
+#define CONTRACT_VIOLATION(violationmask)
+#define CONDITIONAL_CONTRACT_VIOLATION(violationMask, condition)
+#define PERMANENT_CONTRACT_VIOLATION(violationMask, reasonEnum)
+#endif
+
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// Holder for setting up a faultforbid region
+class FaultForbidHolder
+{
+ public:
+ DEBUG_NOINLINE FaultForbidHolder(BOOL fConditional, BOOL fAlloc, const char *szFunction, const char *szFile, int lineNum)
+ {
+ SCAN_SCOPE_BEGIN;
+ STATIC_CONTRACT_FORBID_FAULT;
+
+ m_fConditional = fConditional;
+ if (m_fConditional)
+ {
+ m_pClrDebugState = GetClrDebugState(fAlloc);
+
+ //
+ // If we fail to get a debug state, then we must not be allocating and
+ // we simply no-op this holder.
+ //
+ if (m_pClrDebugState == NULL)
+ {
+ _ASSERTE(!fAlloc);
+ m_fConditional = FALSE;
+ return;
+ }
+
+ m_oldClrDebugState = *m_pClrDebugState;
+
+ m_pClrDebugState->ViolationMaskReset( FaultViolation|FaultNotFatal );
+ m_pClrDebugState->SetFaultForbid();
+
+ m_ContractStackRecord.m_szFunction = szFunction;
+ m_ContractStackRecord.m_szFile = szFile;
+ m_ContractStackRecord.m_lineNum = lineNum;
+ m_ContractStackRecord.m_testmask = (Contract::ALL_Disabled & ~((UINT)(Contract::FAULT_Mask))) | Contract::FAULT_Forbid;
+ m_ContractStackRecord.m_construct = "FAULT_FORBID";
+ m_pClrDebugState->LinkContractStackTrace( &m_ContractStackRecord );
+ }
+ }
+
+ DEBUG_NOINLINE ~FaultForbidHolder()
+ {
+ SCAN_SCOPE_END;
+
+ if (m_fConditional)
+ {
+ *m_pClrDebugState = m_oldClrDebugState;
+ }
+ }
+
+ private:
+ ClrDebugState *m_pClrDebugState;
+ ClrDebugState m_oldClrDebugState;
+ BOOL m_fConditional;
+ ContractStackRecord m_ContractStackRecord;
+
+};
+#endif // ENABLE_CONTRACTS_IMPL
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+#define FAULT_FORBID() FaultForbidHolder _ffh(TRUE, TRUE, __FUNCTION__, __FILE__, __LINE__);
+#define FAULT_FORBID_NO_ALLOC() FaultForbidHolder _ffh(TRUE, FALSE, __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_FAULT_FORBID(cond) FaultForbidHolder _ffh(cond, TRUE, __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_FAULT_FORBID_NO_ALLOC(cond) FaultForbidHolder _ffh(cond, FALSE, __FUNCTION__, __FILE__, __LINE__);
+
+#else // ENABLE_CONTRACTS_IMPL
+
+#define FAULT_FORBID() ;
+#define FAULT_FORBID_NO_ALLOC() ;
+#define MAYBE_FAULT_FORBID(cond) ;
+#define MAYBE_FAULT_FORBID_NO_ALLOC(cond) ;
+
+#endif // ENABLE_CONTRACTS_IMPL
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+inline BOOL AreFaultsForbiddenHelper()
+{
+ STATIC_CONTRACT_DEBUG_ONLY;
+ STATIC_CONTRACT_NOTHROW;
+
+ ClrDebugState *pClrDebugState = CheckClrDebugState();
+ if (!pClrDebugState)
+ {
+ // By default, faults are not forbidden. Not the most desirable default
+ // but we'd never get this debug infrastructure bootstrapped otherwise.
+ return FALSE;
+ }
+ else
+ {
+ return pClrDebugState->IsFaultForbid() && (!(pClrDebugState->ViolationMask() & (FaultViolation|FaultNotFatal|BadDebugState)));
+ }
+}
+
+#define ARE_FAULTS_FORBIDDEN() AreFaultsForbiddenHelper()
+#else
+
+// If you got an error about ARE_FAULTS_FORBIDDEN being undefined, it's because you tried
+// to use this predicate in a free build outside of a CONTRACT or ASSERT.
+//
+#define ARE_FAULTS_FORBIDDEN() (sizeof(YouCannotUseThisHere) != 0)
+#endif
+
+
+// This allows a fault-forbid region to invoke a non-mandatory allocation, such as for the
+// purpose of growing a lookaside cache (if the allocation fails, the code can abandon the
+// cache growing operation without negative effect.)
+//
+// Although it's implemented using CONTRACT_VIOLATION(), it's not a bug to have this in the code.
+//
+// It *is* a bug to use this to hide a situation where an OOM is genuinely fatal but not handled.
+#define FAULT_NOT_FATAL() CONTRACT_VIOLATION(FaultNotFatal)
+
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+//------------------------------------------------------------------------------------
+// Underlying class support for TRIGGERS_TYPE_LOAD and OVERRIDE_TYPE_LOAD_LEVEL_LIMIT.
+// Don't reference this class directly. Use the macros.
+//------------------------------------------------------------------------------------
+class LoadsTypeHolder
+{
+ public:
+ LoadsTypeHolder(BOOL fConditional,
+ UINT newLevel,
+ BOOL fEnforceLevelChangeDirection,
+ const char *szFunction,
+ const char *szFile,
+ int lineNum
+ );
+
+ ~LoadsTypeHolder();
+
+ private:
+ ClrDebugState *m_pClrDebugState;
+ ClrDebugState m_oldClrDebugState;
+ BOOL m_fConditional;
+ ContractStackRecord m_contractStackRecord;
+
+};
+
+#endif // ENABLE_CONTRACTS_IMPL
+
+
+//------------------------------------------------------------------------------------
+// TRIGGERS_TYPE_LOAD(newLevel)
+// Works just LOADS_TYPE in contracts but lets you protect individual scopes
+//
+// OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel)
+// Sets a new limit just like TRIGGERS_TYPE_LOAD but does not restrict you
+// to decreasing the limit. Only the loader should use this and only when it
+// can prove structurally that no recursion will occur as a result.
+//------------------------------------------------------------------------------------
+#ifdef ENABLE_CONTRACTS_IMPL
+
+#define TRIGGERS_TYPE_LOAD(newLevel) LoadsTypeHolder _lth(TRUE, newLevel, TRUE, __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_TRIGGERS_TYPE_LOAD(newLevel, fEnable) LoadsTypeHolder _lth(fEnable, newLevel, TRUE, __FUNCTION__, __FILE__, __LINE__);
+#define OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel) LoadsTypeHolder _lth(TRUE, newLevel, FALSE, __FUNCTION__, __FILE__, __LINE__);
+#define MAYBE_OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel, fEnable) LoadsTypeHolder _lth(fEnable, newLevel, FALSE, __FUNCTION__, __FILE__, __LINE__);
+
+#else // ENABLE_CONTRACTS_IMPL
+
+#define TRIGGERS_TYPE_LOAD(newLevel)
+#define MAYBE_TRIGGERS_TYPE_LOAD(newLevel, fEnable)
+#define OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel)
+#define MAYBE_OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(newLevel, fEnable)
+
+#endif // ENABLE_CONTRACTS_IMPL
+
+
+
+#ifdef ENABLE_CONTRACTS_IMPL
+class PAL_TryMarker
+{
+public:
+ DEBUG_NOINLINE void Enter();
+ DEBUG_NOINLINE void Leave();
+};
+
+#define PAL_ENTER_THROWS_REGION \
+ PAL_TryMarker __throwsHolder_onlyOneAllowedPerScope; \
+ __throwsHolder_onlyOneAllowedPerScope.Enter();
+
+#define PAL_LEAVE_THROWS_REGION \
+ __throwsHolder_onlyOneAllowedPerScope.Leave();
+
+// This sets up a marker that says its okay to throw on this thread. This is not a public macro, and should only be
+// used from within the implementation of various try/catch macros.
+class ClrTryMarkerHolder
+{
+public:
+ DEBUG_NOINLINE ClrTryMarkerHolder()
+ {
+ SCAN_SCOPE_BEGIN;
+ STATIC_CONTRACT_THROWS;
+
+ m_pClrDebugState = GetClrDebugState();
+ m_oldOkayToThrowValue = m_pClrDebugState->IsOkToThrow();
+ m_pClrDebugState->SetOkToThrow();
+ }
+
+ DEBUG_NOINLINE ~ClrTryMarkerHolder()
+ {
+ SCAN_SCOPE_END;
+
+ m_pClrDebugState->SetOkToThrow( m_oldOkayToThrowValue );
+ }
+
+private:
+ BOOL m_oldOkayToThrowValue;
+ ClrDebugState *m_pClrDebugState;
+};
+
+#define CLR_TRY_MARKER() ClrTryMarkerHolder ___tryMarkerHolder;
+
+#else // ENABLE_CONTRACTS_IMPL
+
+#define CLR_TRY_MARKER()
+#define PAL_ENTER_THROWS_REGION
+#define PAL_LEAVE_THROWS_REGION
+
+#endif
+
+#ifdef ENABLE_CONTRACTS_IMPL
+// Note: This routine will create a ClrDebugState if called for the first time.
+// It cannot return NULL (see comment for InitClrDebugState).
+inline ClrDebugState *GetClrDebugState(BOOL fAlloc)
+{
+ STATIC_CONTRACT_LIMITED_METHOD;
+ STATIC_CONTRACT_SO_NOT_MAINLINE;
+
+ ClrDebugState *pState = CheckClrDebugState();
+
+ if (pState)
+ {
+ return pState;
+ }
+
+ if (fAlloc)
+ {
+ return CLRInitDebugState();
+ }
+
+ return NULL;
+}
+#endif // ENABLE_CONTRACTS_IMPL
+
+#ifdef FEATURE_STACK_PROBE
+
+#ifdef ENABLE_CONTRACTS_IMPL
+class SONotMainlineHolder
+{
+ public:
+ DEBUG_NOINLINE void Enter()
+ {
+ SCAN_SCOPE_BEGIN;
+ STATIC_CONTRACT_SO_NOT_MAINLINE;
+
+ m_pClrDebugState = GetClrDebugState();
+ if (m_pClrDebugState)
+ {
+ m_oldSONotMainlineValue = m_pClrDebugState->IsSONotMainline();
+ m_pClrDebugState->SetSONotMainline();
+ }
+ }
+
+ DEBUG_NOINLINE void Leave()
+ {
+ SCAN_SCOPE_END;
+
+ m_pClrDebugState = CheckClrDebugState();
+ if (m_pClrDebugState)
+ {
+ m_pClrDebugState->SetSONotMainline( m_oldSONotMainlineValue );
+ }
+ }
+
+ private:
+ BOOL m_oldSONotMainlineValue;
+ ClrDebugState *m_pClrDebugState;
+};
+
+#define ENTER_SO_NOT_MAINLINE_CODE \
+ SONotMainlineHolder __soNotMainlineHolder; \
+ __soNotMainlineHolder.Enter();
+
+#define LEAVE_SO_NOT_MAINLINE_CODE \
+ __soNotMainlineHolder.Leave();
+
+
+class AutoCleanupSONotMainlineHolder : public SONotMainlineHolder
+{
+ public:
+ DEBUG_NOINLINE AutoCleanupSONotMainlineHolder()
+ {
+ SCAN_SCOPE_BEGIN;
+ STATIC_CONTRACT_SO_NOT_MAINLINE;
+
+ Enter();
+ }
+
+ DEBUG_NOINLINE ~AutoCleanupSONotMainlineHolder()
+ {
+ SCAN_SCOPE_END;
+
+ Leave();
+ }
+};
+
+#define SO_NOT_MAINLINE_FUNCTION \
+ AutoCleanupSONotMainlineHolder __soNotMainlineHolder;
+
+#define SO_NOT_MAINLINE_REGION() \
+ AutoCleanupSONotMainlineHolder __soNotMainlineHolder;
+
+#else // ENABLE_CONTRACTS_IMPL
+#define SO_NOT_MAINLINE_FUNCTION STATIC_CONTRACT_SO_NOT_MAINLINE
+#define SO_NOT_MAINLINE_REGION() STATIC_CONTRACT_SO_NOT_MAINLINE
+#define ENTER_SO_NOT_MAINLINE_CODE
+#define LEAVE_SO_NOT_MAINLINE_CODE
+#endif
+
+#else // FEATURE_STACK_PROBE
+
+#define SO_NOT_MAINLINE_FUNCTION
+#define SO_NOT_MAINLINE_REGION()
+#define ENTER_SO_NOT_MAINLINE_CODE
+#define LEAVE_SO_NOT_MAINLINE_CODE
+
+#endif // FEATURE_STACK_PROBE
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+class HostNoCallHolder
+{
+ public:
+ DEBUG_NOINLINE HostNoCallHolder()
+ {
+ SCAN_SCOPE_BEGIN;
+ STATIC_CONTRACT_HOST_NOCALLS;
+
+ m_clrDebugState = GetClrDebugState();
+ m_previousState = m_clrDebugState->SetHostCaller(FALSE);
+ }
+
+ DEBUG_NOINLINE ~HostNoCallHolder()
+ {
+ SCAN_SCOPE_END;
+
+ m_clrDebugState->SetHostCaller(m_previousState);
+ }
+
+ private:
+ BOOL m_previousState;
+ ClrDebugState* m_clrDebugState;
+
+};
+
+#define BEGIN_HOST_NOCALL_CODE \
+ { \
+ HostNoCallHolder __hostNoCallHolder; \
+ CantAllocHolder __cantAlloc;
+
+#define END_HOST_NOCALL_CODE \
+ }
+
+#else // ENABLE_CONTRACTS_IMPL
+#define BEGIN_HOST_NOCALL_CODE \
+ { \
+ CantAllocHolder __cantAlloc; \
+
+#define END_HOST_NOCALL_CODE \
+ }
+#endif
+
+#ifdef ENABLE_CONTRACTS_IMPL
+
+class GetThreadAllowedHolder
+{
+ public:
+ GetThreadAllowedHolder(BOOL newState)
+ {
+ m_clrDebugState = ::GetClrDebugState();
+ m_previousState = m_clrDebugState->SetGetThreadAllowed(newState);
+ }
+
+ ~GetThreadAllowedHolder()
+ {
+ m_clrDebugState->SetGetThreadAllowed(m_previousState);
+ }
+
+private:
+ BOOL m_previousState;
+ ClrDebugState* m_clrDebugState;
+};
+
+// When in an EE_THREAD_NOT_REQUIRED contracted scope, it's expected that the
+// function does not assume an EE Thread object is available in TLS. Either
+// GetThread() is never called, or any code path that requires a Thread
+// has another code path that deals with the absence of a Thread. Any call to
+// to GetThread() must be bracketed with BEGIN_GETTHREAD_ALLOWED /
+// END_GETTHREAD_ALLOWED to avoid bogus asserts (the short-form
+// GetThreadNULLOk() may be used as well). However, this is only allowed if visual
+// inspection of the call site makes it patently obvious that the function deals
+// appropriately with the GetThread() == NULL case (or that case has already been
+// dealt with and control has exited before the BEGIN_GETTHREAD_ALLOWED /
+// END_GETTHREAD_ALLOWED block.
+//
+// These use holder objects, which causes the compiler to generate EH code and prevent
+// inlining. So try to avoid these in small, downstream functions (like inline
+// EE Thread member functions). Use the _IN_NO_THROW_REGION variants below instead.
+
+#define BEGIN_GETTHREAD_ALLOWED \
+ { \
+ GetThreadAllowedHolder __getThreadAllowedHolder(TRUE); \
+
+#define END_GETTHREAD_ALLOWED \
+ }
+
+// These are lighter-weight versions of BEGIN_GETTHREAD_ALLOWED /
+// END_GETTHREAD_ALLOWED. These don't use holders, so be sure only to
+// use these to bracket code that won't throw exceptions
+#define BEGIN_GETTHREAD_ALLOWED_IN_NO_THROW_REGION \
+ { \
+ ClrDebugState * __clrDebugState = ::GetClrDebugState(); \
+ BOOL __previousState = __clrDebugState->SetGetThreadAllowed(TRUE); \
+
+#define END_GETTHREAD_ALLOWED_IN_NO_THROW_REGION \
+ __clrDebugState->SetGetThreadAllowed(__previousState); \
+ }
+
+#else // ENABLE_CONTRACTS_IMPL
+#define BEGIN_GETTHREAD_ALLOWED
+#define END_GETTHREAD_ALLOWED
+#define BEGIN_GETTHREAD_ALLOWED_IN_NO_THROW_REGION
+#define END_GETTHREAD_ALLOWED_IN_NO_THROW_REGION
+#endif
+
+#if defined(ENABLE_CONTRACTS_IMPL)
+
+// Macros to indicate we're taking or releasing locks
+
+// Most general macros, not used directly
+#define LOCK_TAKEN_MULTIPLE(dbgStateLockType, cEntrances, pvLock) \
+ ::GetClrDebugState()->LockTaken((dbgStateLockType), (cEntrances), (void*) (pvLock), __FUNCTION__, __FILE__, __LINE__)
+#define LOCK_RELEASED_MULTIPLE(dbgStateLockType, cExits, pvLock) \
+ ::GetClrDebugState()->LockReleased((dbgStateLockType), (cExits), (void*) (pvLock))
+
+// Use these only if you need to force multiple entrances or exits in a single
+// line (e.g., to restore the lock to a previous state). CRWLock in vm\rwlock.cpp does this
+#define EE_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock) \
+ LOCK_TAKEN_MULTIPLE(kDbgStateLockType_EE, cEntrances, pvLock)
+#define EE_LOCK_RELEASED_MULTIPLE(cExits, pvLock) \
+ LOCK_RELEASED_MULTIPLE(kDbgStateLockType_EE, cExits, pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN_MULTIPLE(cEntrances, pvLock) \
+ LOCK_TAKEN_MULTIPLE(kDbgStateLockType_HostBreakableCrst, cEntrances, pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED_MULTIPLE(cExits, pvLock) \
+ LOCK_RELEASED_MULTIPLE(kDbgStateLockType_HostBreakableCrst, cExits, pvLock)
+#define USER_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock) \
+ LOCK_TAKEN_MULTIPLE(kDbgStateLockType_User, cEntrances, pvLock)
+#define USER_LOCK_RELEASED_MULTIPLE(cExits, pvLock) \
+ LOCK_RELEASED_MULTIPLE(kDbgStateLockType_User, cExits, pvLock)
+
+// These are most typically used
+#define EE_LOCK_TAKEN(pvLock) \
+ LOCK_TAKEN_MULTIPLE(kDbgStateLockType_EE, 1, pvLock)
+#define EE_LOCK_RELEASED(pvLock) \
+ LOCK_RELEASED_MULTIPLE(kDbgStateLockType_EE, 1, pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN(pvLock) \
+ LOCK_TAKEN_MULTIPLE(kDbgStateLockType_HostBreakableCrst, 1, pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED(pvLock) \
+ LOCK_RELEASED_MULTIPLE(kDbgStateLockType_HostBreakableCrst, 1, pvLock)
+#define USER_LOCK_TAKEN(pvLock) \
+ LOCK_TAKEN_MULTIPLE(kDbgStateLockType_User, 1, pvLock)
+#define USER_LOCK_RELEASED(pvLock) \
+ LOCK_RELEASED_MULTIPLE(kDbgStateLockType_User, 1, pvLock)
+
+#else // defined(ENABLE_CONTRACTS_IMPL)
+
+#define LOCK_TAKEN_MULTIPLE(dbgStateLockType, cEntrances, pvLock)
+#define LOCK_RELEASED_MULTIPLE(dbgStateLockType, cExits, pvLock)
+#define EE_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock)
+#define EE_LOCK_RELEASED_MULTIPLE(cExits, pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN_MULTIPLE(cEntrances, pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED_MULTIPLE(cExits, pvLock)
+#define USER_LOCK_TAKEN_MULTIPLE(cEntrances, pvLock)
+#define USER_LOCK_RELEASED_MULTIPLE(cExits, pvLock)
+#define EE_LOCK_TAKEN(pvLock)
+#define EE_LOCK_RELEASED(pvLock)
+#define HOST_BREAKABLE_CRST_TAKEN(pvLock)
+#define HOST_BREAKABLE_CRST_RELEASED(pvLock)
+#define USER_LOCK_TAKEN(pvLock)
+#define USER_LOCK_RELEASED(pvLock)
+
+#endif // defined(ENABLE_CONTRACTS_IMPL)
+
+#if defined(ENABLE_CONTRACTS_IMPL)
+
+// Abbreviation for an assert that is only considered if there is a valid
+// ClrDebugState available. Useful if you want to assert based on the value
+// of GetDbgStateLockCount(), where a return of 0 (the default if there is no
+// valid ClrDebugState available) would cause your assert to fire. The variable
+// __pClrDebugState is set to the current ClrDebugState, and may be used within
+// your assert expression
+#define ASSERT_UNLESS_NO_DEBUG_STATE(e) \
+ { \
+ ClrDebugState * __pClrDebugState = GetClrDebugState(); \
+ _ASSERTE(((__pClrDebugState->ViolationMask() & BadDebugState) != 0) || (e)); \
+ }
+
+#else // defined(ENABLE_CONTRACTS_IMPL)
+
+#define ASSERT_UNLESS_NO_DEBUG_STATE(e)
+
+#endif // defined(ENABLE_CONTRACTS_IMPL)
+
+
+//-----------------------------------------------------------------------------
+// Debug support to ensure that nobody calls New on the helper thread.
+// This is for interop debugging.
+// They should be using the InteropSafe heap.
+// Having this in the meantime allows us to
+// assert that the helper thread never calls new, and maintain a finite list of
+// exceptions (bugs).
+// Eventually, all those bugs should be fixed this holder can be completely removed.
+//
+// It is also the case that we disallow allocations when any thread is OS suspended
+// This happens for a short time when we are suspending the EE. We supress both
+// of these.
+//
+// @todo- ideally this would be rolled into the ContractViolation.
+// also, we'd have contract bit for whether APIs can be called on the helper thread.
+// @todo - if we really wanted to be strict, we should make this per-thread.
+//-----------------------------------------------------------------------------
+#ifdef ENABLE_CONTRACTS_IMPL
+extern Volatile<LONG> g_DbgSuppressAllocationAsserts;
+#define SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE CounterHolder _AllowNewOnHelperHolder(&g_DbgSuppressAllocationAsserts);
+#else
+// Nothing in retail since this holder just disabled an assert.
+#define SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Support for contracts in DAC builds
+//
+// At the moment, most of the contract system is disabled in DAC builds.
+// We do however want some simple static contracts in order to support static
+// analysis tools that run on mscordacwks.dll like DacCop.
+// Note that we want these static contracts in both DEBUG and retail builds.
+// We also already get simple static contracts like WRAPPER and LEAF.
+//
+//-----------------------------------------------------------------------------
+#if defined(DACCESS_COMPILE)
+
+// SUPPORTS_DAC is an annotation that says the function is designed to be used in DAC builds.
+// This enables full DacCop analysis on the function, including verifying that all functions that are
+// called also support DAC.
+#define SUPPORTS_DAC do { STATIC_CONTRACT_SUPPORTS_DAC; } while(0)
+
+// Normally a function can be annotated just with WRAPPER_NO_CONTRACT, which (in addition to the normal
+// contract meaning) indicates to DacCop that the function should be considered to support DAC when
+// it is called from a supports-dac function. This is to avoid having to add a DAC-specific contract
+// to all the trivial one-line wrapper functions we have.
+// However, we occasionally want these semantics even for functions which are not appropriate to label
+// as WRAPPER_NO_CONTRACT. For example, a template function may support DAC for certain template arguments,
+// but not others (due to the functions it calls). We want to ensure that when such a function is called
+// in a DAC code path, analysis is enabled on that particular instantiation including checking all of the
+// call targets specific to this template instantiation. But we don't want to require that the call targets
+// for ALL instantiations support dac, since we may not even be using them in DAC code paths. Ideally we'd
+// remove any such code from the DAC build, but this will take time.
+#define SUPPORTS_DAC_WRAPPER do { STATIC_CONTRACT_WRAPPER; } while(0)
+
+// SUPPORTS_DAC_HOST_ONLY indicates that a function is allowed to be called in DAC builds, but rather
+// than being a normal DAC function which operates on marshalled data, it is a host-only utility function
+// that knows nothing about DAC and operates solely on the host. For example, DbgAssertDialog is a utility
+// function for popping assert dialogs - there is nothing DAC-specific about this. Ideally such utility
+// functions would be confined to their own library which had no access to DAC functionality, and which
+// is not analyzed by DacCop. At the moment splitting utilcode into two variations like this is too
+// painful, but we hope to do it in the future (primarily to support functions which can be used in either
+// DAC or host-only mode).
+// WARNING: This contract disables DacCop analysis on the function and any functions it calls, so it
+// should be used very carefully.
+#define SUPPORTS_DAC_HOST_ONLY do { STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY; } while(0)
+
+#else
+#define SUPPORTS_DAC
+#define SUPPORTS_DAC_HOST_ONLY
+#define SUPPORTS_DAC_WRAPPER
+#endif // DACCESS_COMPILE
+
+// LIMITED_METHOD_DAC_CONTRACT is a shortcut for LIMITED_METHOD_CONTRACT and SUPPORTS_DAC. Usefull for one-line inline functions.
+#define LIMITED_METHOD_DAC_CONTRACT LIMITED_METHOD_CONTRACT; SUPPORTS_DAC
+
+//
+// The default contract is the recommended contract for ordinary code.
+// The ordinary code can throw or trigger GC any time, does not operate
+// on raw object refs, etc.
+//
+
+#define STANDARD_VM_CHECK \
+ THROWS; \
+ SO_INTOLERANT; \
+
+#define STANDARD_VM_CONTRACT \
+ CONTRACTL \
+ { \
+ STANDARD_VM_CHECK; \
+ } \
+ CONTRACTL_END; \
+
+#define STATIC_STANDARD_VM_CONTRACT \
+ STATIC_CONTRACT_THROWS; \
+ STATIC_CONTRACT_GC_TRIGGERS; \
+ STATIC_CONTRACT_MODE_PREEMPTIVE; \
+ STATIC_CONTRACT_SO_INTOLERANT
+
+#define AFTER_CONTRACTS
+#include "volatile.h"
+
+#endif // CONTRACT_H_