Esempio n. 1
0
BOOL DebugBreakOnAssert()
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;
    STATIC_CONTRACT_DEBUG_ONLY;
    STATIC_CONTRACT_FORBID_FAULT;
    STATIC_CONTRACT_SUPPORTS_DAC;

    // ok for debug-only code to take locks
    CONTRACT_VIOLATION(TakesLockViolation);

    BOOL fRet = FALSE;

#ifndef DACCESS_COMPILE  
    static ConfigDWORD fDebugBreak;
    //
    // we don't want this config key to affect mscordacwks as well!
    //
    EX_TRY
    {
        fRet = fDebugBreak.val(CLRConfig::INTERNAL_DebugBreakOnAssert);
    }
    EX_CATCH
    {
    }
    EX_END_CATCH(SwallowAllExceptions);
#endif // DACCESS_COMPILE

    return fRet;
}
Esempio n. 2
0
BOOL RaiseExceptionOnAssert(RaiseOnAssertOptions option = rTestAndRaise)
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;
    STATIC_CONTRACT_DEBUG_ONLY;
    STATIC_CONTRACT_FORBID_FAULT;
    STATIC_CONTRACT_SUPPORTS_DAC;

    // ok for debug-only code to take locks
    CONTRACT_VIOLATION(TakesLockViolation);

    DWORD fRet = 0;

#if !defined(DACCESS_COMPILE)
    static ConfigDWORD fRaiseExceptionOnAssert;
    //
    // we don't want this config key to affect mscordacwks as well!
    //
    EX_TRY
    {
        fRet = fRaiseExceptionOnAssert.val(CLRConfig::INTERNAL_RaiseExceptionOnAssert);
    }
    EX_CATCH
    {
    }
    EX_END_CATCH(SwallowAllExceptions);

    if (option == rTestAndRaise && fRet != 0)
    {
        DoRaiseExceptionOnAssert(fRet);
    }
#endif // !DACCESS_COMPILE

    return fRet != 0;
}
Esempio n. 3
0
VOID EnterLogLock()
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;

    // We don't care about violating CANNOT_TAKE_LOCK in debug-only builds, and it's
    // rather hard to care about this, as we LOG all over the place.
    CONTRACT_VIOLATION(TakesLockViolation);

    if(LogFileMutex != 0)
    {
        DWORD status;
        status = ClrWaitForMutex(LogFileMutex, INFINITE, FALSE);
        _ASSERTE(WAIT_OBJECT_0 == status);
    }
}
Esempio n. 4
0
// Full version handles metadata caching, which Release() needs to coordinate with. 
// Thus Release() is in a satellite lib.
ULONG RegMeta::Release()
{
    // This is called during cleanup.  We can not fail this call by probing.
    // As long as we make sure the cleanup does not use too much space through 
    // BEGIN_CLEANUP_ENTRYPOINT, we are OK.
    CONTRACT_VIOLATION (SOToleranceViolation);
    BEGIN_CLEANUP_ENTRYPOINT;

#if defined(FEATURE_METADATA_IN_VM)
    _ASSERTE(!m_bCached || LOADEDMODULES::IsEntryInList(this));
#else
    _ASSERTE(!m_bCached);
#endif // FEATURE_METADATA_IN_VM 
    BOOL  bCached = m_bCached;
    ULONG cRef = InterlockedDecrement(&m_cRef);
    // NOTE: 'this' may be unsafe after this point, if the module is cached, and
    //  another thread finds the module in the cache, releases it, and deletes it
    //  before we get around to deleting it. (That's why we must make a local copy
    //  of m_bCached.)
    // If no references left...
    if (cRef == 0)
    {
        if (!bCached)
        {   // If the module is not (was not) cached, no other thread can have
            //  discovered the module, so this thread can now safely delete it.
            delete this;
        }
#if defined(FEATURE_METADATA_IN_VM)
        else if (LOADEDMODULES::RemoveModuleFromLoadedList(this))
        {   // If the module was cached, RemoveModuleFromLoadedList() will try to
            //  safely un-publish the module, and if it succeeds, no other thread
            //  has (or will) discover the module, so this thread can delete it.
            m_bCached = false;
            delete this;
        }
#endif // FEATURE_METADATA_IN_VM 
    }
    END_CLEANUP_ENTRYPOINT
    
    return cRef;
} // RegMeta::Release
Esempio n. 5
0
//*****************************************************************************
// This function will handle ignore codes and tell the user what is happening.
//*****************************************************************************
bool _DbgBreakCheck(
    LPCSTR      szFile,
    int         iLine,
    LPCSTR      szExpr, 
    BOOL        fConstrained)
{
    STATIC_CONTRACT_THROWS;
    STATIC_CONTRACT_GC_NOTRIGGER;
    STATIC_CONTRACT_FORBID_FAULT;
    STATIC_CONTRACT_DEBUG_ONLY;

    RaiseExceptionOnAssert(rTestAndRaise);

    if (DebugBreakOnAssert())
    {
        DebugBreak();
    }

    DBGIGNORE* pDBGIFNORE = GetDBGIGNORE();
    _DBGIGNOREDATA *psData;
    int i;

    // Check for ignore all.
    for (i = 0, psData = pDBGIFNORE->Ptr();  i < pDBGIFNORE->Count();  i++, psData++)
    {
        if (psData->iLine == iLine && SString::_stricmp(psData->rcFile, szFile) == 0 && psData->bIgnore == true)
        {
            return false;
        }
    }

    CONTRACT_VIOLATION(FaultNotFatal | GCViolation | TakesLockViolation);
    
    SString debugOutput;
    SString dialogOutput;
    SString modulePath;
    SString dialogTitle;
    SString dialogIgnoreMessage;
    BOOL formattedMessages = FALSE;
    
    // If we are low on memory we cannot even format a message. If this happens we want to
    // contain the exception here but display as much information as we can about the exception.
    if (!fConstrained) 
    {
        EX_TRY
        {
            ClrGetModuleFileName(0, modulePath);
            debugOutput.Printf(
                W("\nAssert failure(PID %d [0x%08x], Thread: %d [0x%04x]): %hs\n")
                W("    File: %hs Line: %d\n")
                W("    Image: "),
                GetCurrentProcessId(), GetCurrentProcessId(),
                GetCurrentThreadId(), GetCurrentThreadId(),
                szExpr, szFile, iLine);
            debugOutput.Append(modulePath);
            debugOutput.Append(W("\n\n"));
         
            // Change format for message box.  The extra spaces in the title
            // are there to get around format truncation.
            dialogOutput.Printf(
                W("%hs\n\n%hs, Line: %d\n\nAbort - Kill program\nRetry - Debug\nIgnore - Keep running\n")
                W("\n\nImage:\n"), szExpr, szFile, iLine);
            dialogOutput.Append(modulePath);
            dialogOutput.Append(W("\n"));
            dialogTitle.Printf(W("Assert Failure (PID %d, Thread %d/0x%04x)"),
                GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId());
            
            dialogIgnoreMessage.Printf(W("Ignore the assert for the rest of this run?\nYes - Assert will never fire again.\nNo - Assert will continue to fire.\n\n%hs\nLine: %d\n"),
                szFile, iLine);

            formattedMessages = TRUE;
        }
        EX_CATCH
        {            
        }
        EX_END_CATCH(SwallowAllExceptions);
    }
Esempio n. 6
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();
    }
}