Beispiel #1
0
//=========================================================================
// Asserts if lock mode is PREEMPTIVE and thread in a GC_NOTRIGGER contract
//=========================================================================        
void SimpleRWLock::CheckGCNoTrigger()
{
    STATIC_CONTRACT_NOTHROW;

    // On PREEMPTIVE locks we'll toggle the GC mode, so we better not be in a GC_NOTRIGGERS region
    if (m_gcMode == PREEMPTIVE)
    {
        ClrDebugState *pClrDebugState = CheckClrDebugState();
        if (pClrDebugState)
        {
            if (pClrDebugState->GetGCNoTriggerCount())
            {
                // If we have no thread object, we won't be toggling the GC.  This is the case, 
                // for example, on the debugger helper thread which is always GC_NOTRIGGERS.
                if (GetThreadNULLOk() != NULL) 
                {
                    if (!( (GCViolation|BadDebugState) & pClrDebugState->ViolationMask()))
                    {
                        CONTRACT_ASSERT("You cannot enter a lock in a GC_NOTRIGGER region.",
                                        Contract::GC_NoTrigger,
                                        Contract::GC_Mask,
                                        __FUNCTION__,
                                        __FILE__,
                                        __LINE__);
                    }
                }
            }

            // The mode checks and enforcement of GC_NOTRIGGER during the lock are done in SimpleRWLock::PostEnter().
        }
    }
}
Beispiel #2
0
        WinWrapperContract(const char *szFunction, const char *szFile, int lineNum)
        {
            CANNOT_HAVE_CONTRACT;

            m_pClrDebugState = NULL;
            
            if (gWinWrapperContractRecursionBreak)
            {
                return;
            }

            m_pClrDebugState = GetClrDebugState();

            // Save old debug state
            m_IncomingClrDebugState = *m_pClrDebugState;


            m_pClrDebugState->ViolationMaskReset( ThrowsViolation );

            if (m_pClrDebugState->IsFaultForbid() && !(m_pClrDebugState->ViolationMask() & (FaultViolation|FaultNotFatal|BadDebugState)))
            {
                gWinWrapperContractRecursionBreak = TRUE;

                CONTRACT_ASSERT("INJECT_FAULT called in a FAULTFORBID region.",
                                Contract::FAULT_Forbid,
                                Contract::FAULT_Mask,
                                szFunction,
                                szFile,
                                lineNum
                                );
            }

            
        };
Beispiel #3
0
void EEContract::DoChecks(UINT testmask, __in_z const char *szFunction, __in_z char *szFile, int lineNum)
{
    SCAN_IGNORE_THROW;      // Tell the static contract analyzer to ignore contract violations
    SCAN_IGNORE_FAULT;      // due to the contract checking logic itself.
    SCAN_IGNORE_TRIGGER;
    SCAN_IGNORE_LOCK;
    SCAN_IGNORE_SO;
    
    // Many of the checks below result in calls to GetThread()
    // that work just fine if GetThread() returns NULL, so temporarily
    // allow such calls.
    BEGIN_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;
    m_pThread = GetThread();
    if (m_pThread != NULL)
    {
        m_pClrDebugState = m_pThread->GetClrDebugState();
    }

    // Call our base DoChecks.
    BaseContract::DoChecks(testmask, szFunction, szFile, lineNum);

    m_testmask = testmask;
    m_contractStackRecord.m_testmask = testmask;

    // GC mode check
    switch (testmask & MODE_Mask)
    {
        case MODE_Coop:
            if (m_pThread == NULL || !m_pThread->PreemptiveGCDisabled())
            {
                //
                // Check if this is the debugger helper thread and has the runtime
                // stoppped.  If both of these things are true, then we do not care
                // whether we are in COOP mode or not.
                //
                if ((g_pDebugInterface != NULL) && 
                    g_pDebugInterface->ThisIsHelperThread() &&
                    g_pDebugInterface->IsStopped())
                {
                    break;
                }

                // Pretend that the threads doing GC are in cooperative mode so that code with 
                // MODE_COOPERATIVE contract works fine on them. 
                if (IsGCThread()) 
                {
                    break;
                }

                if (!( (ModeViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
                {
                    if (m_pThread == NULL)
                    {
                        CONTRACT_ASSERT("You must have called SetupThread in order to be in GC Cooperative mode.",
                                        Contract::MODE_Preempt,
                                        Contract::MODE_Mask,
                                        m_contractStackRecord.m_szFunction,
                                        m_contractStackRecord.m_szFile,
                                        m_contractStackRecord.m_lineNum
                                       );
                    }
                    else
                    {
                        CONTRACT_ASSERT("MODE_COOPERATIVE encountered while thread is in preemptive state.",
                                        Contract::MODE_Preempt,
                                        Contract::MODE_Mask,
                                        m_contractStackRecord.m_szFunction,
                                        m_contractStackRecord.m_szFile,
                                        m_contractStackRecord.m_lineNum
                                       );
                    }
                }
            }
            break;

        case MODE_Preempt:
            // Unmanaged threads are considered permanently preemptive so a NULL thread amounts to a passing case here.
            if (m_pThread != NULL && m_pThread->PreemptiveGCDisabled())
            {
                if (!( (ModeViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
                {
                        CONTRACT_ASSERT("MODE_PREEMPTIVE encountered while thread is in cooperative state.",
                                        Contract::MODE_Coop,
                                        Contract::MODE_Mask,
                                        m_contractStackRecord.m_szFunction,
                                        m_contractStackRecord.m_szFile,
                                        m_contractStackRecord.m_lineNum
                                       );
                    }
            }
            break;

        case MODE_Disabled:
            // Nothing
            break;

        default:
            UNREACHABLE();
    }

    // GC Trigger check
    switch (testmask & GC_Mask)
    {
        case GC_Triggers:
            // We don't want to do a full TRIGGERSGC here as this could corrupt
            // OBJECTREF-typed arguments to the function. 
            {
                if (m_pClrDebugState->GetGCNoTriggerCount())
                {
                    if (!( (GCViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
                    {
                        CONTRACT_ASSERT("GC_TRIGGERS encountered in a GC_NOTRIGGER scope",
                                        Contract::GC_NoTrigger,
                                        Contract::GC_Mask,
                                        m_contractStackRecord.m_szFunction,
                                        m_contractStackRecord.m_szFile,
                                        m_contractStackRecord.m_lineNum
                                        );
                    }
                }
            }
            break;

        case GC_NoTrigger:
            m_pClrDebugState->ViolationMaskReset( GCViolation );

                // Inlined BeginNoTriggerGC
            m_pClrDebugState->IncrementGCNoTriggerCount();
            if (m_pThread && m_pThread->m_fPreemptiveGCDisabled)
                {
                m_pClrDebugState->IncrementGCForbidCount();
            }

            break;

        case GC_Disabled:
            // Nothing
            break;

        default:
            UNREACHABLE();
    }

    // Host Triggers check
    switch (testmask & HOST_Mask)
    {
        case HOST_Calls:
            {
                if (!m_pClrDebugState->IsHostCaller())
                {
                    if (!( (HostViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
                    {
                        // Avoid infinite recursion by temporarily allowing HOST_CALLS
                        // violations so that we don't get contract asserts in anything
                        // called downstream of CONTRACT_ASSERT. If we unwind out of
                        // here, our dtor will reset our state to what it was on entry.
                        CONTRACT_VIOLATION(HostViolation);    
                        CONTRACT_ASSERT("HOST_CALLS  encountered in a HOST_NOCALLS scope",
                                        Contract::HOST_NoCalls,
                                        Contract::HOST_Mask,
                                        m_contractStackRecord.m_szFunction,
                                        m_contractStackRecord.m_szFile,
                                        m_contractStackRecord.m_lineNum
                                        );
                    }
                }
            }
            break;

        case HOST_NoCalls:
           //  m_pClrDebugState->ViolationMaskReset( HostViolation );
            m_pClrDebugState->ResetHostCaller();
            break;

        case HOST_Disabled:
            // Nothing
            break;

        default:
            UNREACHABLE();
    }
    END_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;

    // EE Thread-required check
    // NOTE: The following must NOT be inside BEGIN/END_GETTHREAD_ALLOWED, 
    // as the change to m_pClrDebugState->m_allowGetThread below would be
    // overwritten by END_GETTHREAD_ALLOWED.
    switch (testmask & EE_THREAD_Mask)
    {
        case EE_THREAD_Required:
            if (!((EEThreadViolation|BadDebugState) & m_pClrDebugState->ViolationMask()))
            {
                if (m_pThread == NULL)
                {
                    CONTRACT_ASSERT("EE_THREAD_REQUIRED encountered with no current EE Thread object in TLS.",
                                    Contract::EE_THREAD_Required,
                                    Contract::EE_THREAD_Mask,
                                    m_contractStackRecord.m_szFunction,
                                    m_contractStackRecord.m_szFile,
                                    m_contractStackRecord.m_lineNum
                                   );
                }
                else if (!m_pClrDebugState->IsGetThreadAllowed())
                {
                    // In general, it's unsafe for an EE_THREAD_NOT_REQUIRED function to
                    // call an EE_THREAD_REQUIRED function. In cases where it is safe,
                    // you may wrap the call to the EE_THREAD_REQUIRED function inside a
                    // BEGIN/END_GETTHREAD_ALLOWED block, but you may only do so if the
                    // case where GetThread() == NULL is clearly handled in a way that
                    // prevents entry into the BEGIN/END_GETTHREAD_ALLOWED block.
                    CONTRACT_ASSERT("EE_THREAD_REQUIRED encountered in an EE_THREAD_NOT_REQUIRED scope, without an intervening BEGIN/END_GETTHREAD_ALLOWED block.",
                                    Contract::EE_THREAD_Required,
                                    Contract::EE_THREAD_Mask,
                                    m_contractStackRecord.m_szFunction,
                                    m_contractStackRecord.m_szFile,
                                    m_contractStackRecord.m_lineNum
                                   );
                }
            }
            m_pClrDebugState->SetGetThreadAllowed();
            break;

        case EE_THREAD_Not_Required:
            m_pClrDebugState->ResetGetThreadAllowed();
            break;

        case EE_THREAD_Disabled:
            break;

        default:
            UNREACHABLE();
    }
}