diff options
Diffstat (limited to 'src/vm/mdaassistants.cpp')
-rw-r--r-- | src/vm/mdaassistants.cpp | 2352 |
1 files changed, 2352 insertions, 0 deletions
diff --git a/src/vm/mdaassistants.cpp b/src/vm/mdaassistants.cpp new file mode 100644 index 0000000000..cc598c0a6c --- /dev/null +++ b/src/vm/mdaassistants.cpp @@ -0,0 +1,2352 @@ +// 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. + + +#include "common.h" +#ifdef MDA_SUPPORTED +#include "mda.h" +#include "mdaassistants.h" +#include "field.h" +#include "dllimport.h" +#ifdef FEATURE_COMINTEROP +#include "runtimecallablewrapper.h" +#include "comcallablewrapper.h" +#include "comcache.h" +#include "comtoclrcall.h" +#include "mlinfo.h" +#endif +#include "sigformat.h" +#include "fieldmarshaler.h" +#include "dllimportcallback.h" +#include "dbginterface.h" +#include "finalizerthread.h" + +#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT +#include "olecontexthelpers.h" +#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT + +#ifdef MDA_SUPPORTED +//// +//// Mda Assistants +//// + + +// Why is ANYTHING in here marked SO_TOLERANT?? Presumably some of them are called from managed code???? + + +// +// MdaFramework +// +void MdaFramework::DumpDiagnostics() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_NOT_MAINLINE; + } + CONTRACTL_END; + + ManagedDebuggingAssistants* pMda = g_mdaStaticHeap.m_pMda; + +#ifdef _DEBUG + if (m_dumpSchemaSchema) + { + MdaXmlElement* pXmlSchemaSchema = pMda->m_pSchemaSchema->ToXml(pMda->m_pMdaXmlIndustry); +// MdaXmlMessage::SendMessage(pXmlSchemaSchema, TRUE, pMda->m_pSchemaSchema); + } + + if (m_dumpAssistantSchema) + { + MdaXmlElement* pXmlAssistantMsgSchema = pMda->m_pAssistantMsgSchema->ToXml(pMda->m_pMdaXmlIndustry); +// MdaXmlMessage::SendMessage(pXmlAssistantMsgSchema, TRUE, pMda->m_pSchemaSchema); + } + + if (m_dumpAssistantMsgSchema) + { + MdaXmlElement* pXmlAssistantSchema = pMda->m_pAssistantSchema->ToXml(pMda->m_pMdaXmlIndustry); +// MdaXmlMessage::SendMessage(pXmlAssistantSchema, TRUE, pMda->m_pSchemaSchema); + } +#endif +} + +#ifdef _DEBUG +extern BOOL g_bMdaDisableAsserts; +#endif + +void MdaFramework::Initialize(MdaXmlElement* pXmlInput) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + +#ifdef _DEBUG + ManagedDebuggingAssistants* pMda = g_mdaStaticHeap.m_pMda; + g_bMdaDisableAsserts = pXmlInput->GetAttributeValueAsBool(MdaAttrDecl(DisableAsserts)); + MdaXmlElement* pXmlDiagnostics = pXmlInput->GetChild(MdaElemDecl(Diagnostics)); + + if (pXmlDiagnostics) + { + m_dumpSchemaSchema = pXmlDiagnostics->GetAttributeValueAsBool(MdaAttrDecl(DumpSchemaSchema), FALSE); + m_dumpAssistantSchema = pXmlDiagnostics->GetAttributeValueAsBool(MdaAttrDecl(DumpAssistantSchema), FALSE); + m_dumpAssistantMsgSchema = pXmlDiagnostics->GetAttributeValueAsBool(MdaAttrDecl(DumpAssistantMsgSchema), FALSE); + } +#endif +} + +// +// MdaGcUnmanagedToManaged +// +void MdaGcUnmanagedToManaged::TriggerGC() +{ + WRAPPER_NO_CONTRACT; + + TriggerGCForMDAInternal(); +} + + +// +// MdaGcManagedToUnmanaged +// +void MdaGcManagedToUnmanaged::TriggerGC() +{ + WRAPPER_NO_CONTRACT; + + TriggerGCForMDAInternal(); +} + +void TriggerGCForMDAInternal() +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_COOPERATIVE; + SO_TOLERANT; + } + CONTRACTL_END; + + BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return); + + EX_TRY + { + GCHeap::GetGCHeap()->GarbageCollect(); + +#ifdef FEATURE_SYNCHRONIZATIONCONTEXT_WAIT + // + // It is very dangerous to wait for finalizer thread here if we are inside a wait + // operation, as the wait operation might call into interop which calls this MDA + // and call into FinalizerThreadWait. In this case, we might run into infinite recursion: + // SynchronizationContext.Wait -> P/Invoke -> WaitForPendingFinalizer -> + // SynchronizationContext.Wait .... + // + // So, if we are inside a SyncContext.Wait, don't call out to FinalizerThreadWait + // + if (!GetThread()->HasThreadStateNC(Thread::TSNC_InsideSyncContextWait)) +#endif // FEATURE_SYNCHRONIZATIONCONTEXT_WAIT + // It is possible that user code run as part of finalization will wait for this thread. + // To avoid deadlocks, we limit the wait time to 10 seconds (an arbitrary number). + FinalizerThread::FinalizerThreadWait(10 * 1000); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); + + END_SO_INTOLERANT_CODE; +} + +// +// MdaCallbackOnCollectedDelegate +// +/* +MdaCallbackOnCollectedDelegate::~MdaCallbackOnCollectedDelegate() +{ + WRAPPER_NO_CONTRACT; + + if (m_pList && m_size) + { + for (int i=0; i < m_size; i++) + ReplaceEntry(i, NULL); + + delete[] m_pList; + } +} +*/ + +void MdaCallbackOnCollectedDelegate::ReportViolation(MethodDesc* pMD) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + MdaXmlElement* pDelegate = pXml->AddChild(MdaElemDecl(Delegate)); + StackSString delegateName; + + if(pMD) + { + AsMdaAssistant()->OutputMethodDesc(pMD, pDelegate); + AsMdaAssistant()->ToString(delegateName, pMD); + } + + msg.SendMessagef(MDARC_CALLBACK_ON_COLLECTED_DELEGATE, delegateName.GetUnicode()); +} + +void MdaCallbackOnCollectedDelegate::AddToList(UMEntryThunk* pEntryThunk) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_INTOLERANT; + PRECONDITION(CheckPointer(pEntryThunk)); + } + CONTRACTL_END; + + // Get an index to use. + ULONG oldIndex = m_iIndex; + ULONG newIndex = oldIndex + 1; + if (newIndex >= (ULONG)m_size) + newIndex = 0; + + while ((ULONG)FastInterlockCompareExchange((LONG*)&m_iIndex, newIndex, oldIndex) != oldIndex) + { + oldIndex = m_iIndex; + newIndex = oldIndex + 1; + if (newIndex >= (ULONG)m_size) + newIndex = 0; + } + + // We successfully incremented the index and can use the oldIndex value as our entry. + ReplaceEntry(oldIndex, pEntryThunk); +} + +void MdaCallbackOnCollectedDelegate::ReplaceEntry(int index, UMEntryThunk* pET) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_INTOLERANT; + PRECONDITION((index >= 0) && (index < m_size)); + PRECONDITION(CheckPointer(m_pList)); + } + CONTRACTL_END; + + if ((m_pList) && (m_size > index) && (index >= 0)) + { + UMEntryThunk* pETTemp = m_pList[index]; + while (FastInterlockCompareExchangePointer((LPVOID*)&m_pList[index], (LPVOID)pET, (LPVOID)pETTemp) != (LPVOID)pETTemp) + { + pETTemp = m_pList[index]; + } + + if (NULL != pETTemp) + { + pETTemp->Terminate(); + } + } +} + +#ifdef FEATURE_COMINTEROP + +void MdaInvalidMemberDeclaration::ReportViolation(ComCallMethodDesc *pCMD, OBJECTREF *pExceptionObj) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_COOPERATIVE; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + TypeHandle th; + StackSString strMemberName; + StackSString strTypeName; + StackSString strMessage; + + GetExceptionMessage(*pExceptionObj, strMessage); + + if (pCMD->IsFieldCall()) + { + FieldDesc *pFD = pCMD->GetFieldDesc(); + + th = pFD->GetFieldTypeHandleThrowing(); + strMemberName.SetUTF8(pFD->GetName()); + AsMdaAssistant()->OutputFieldDesc(pFD, pXml->AddChild(MdaElemDecl(Field))); + } + else + { + MethodDesc *pMD = pCMD->GetCallMethodDesc(); + + th = TypeHandle(pMD->GetMethodTable()); + strMemberName.SetUTF8(pMD->GetName()); + AsMdaAssistant()->OutputMethodDesc(pMD, pXml->AddChild(MdaElemDecl(Method))); + } + + th.GetName(strTypeName); + + AsMdaAssistant()->OutputTypeHandle(th, pXml->AddChild(MdaElemDecl(Type))); + AsMdaAssistant()->OutputException(pExceptionObj, pXml->AddChild(MdaElemDecl(Exception))); + + msg.SendMessagef(MDARC_INVALID_MEMBER_DECLARATION, + strMemberName.GetUnicode(), strTypeName.GetUnicode(), strMessage.GetUnicode()); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); +} + +#endif //FEATURE_COMINTEROP + + +// +// MdaExceptionSwallowedOnCallFromCom +// +void MdaExceptionSwallowedOnCallFromCom::ReportViolation(MethodDesc *pMD, OBJECTREF *pExceptionObj) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + StackSString strMessage; + StackSString strTypeName; + StackSString strMemberName; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + TypeHandle th = TypeHandle(pMD->GetMethodTable()); + + GetExceptionMessage(*pExceptionObj, strMessage); + th.GetName(strTypeName); + strMemberName.SetUTF8(pMD->GetName()); + + AsMdaAssistant()->OutputMethodDesc(pMD, pXml->AddChild(MdaElemDecl(Method))); + AsMdaAssistant()->OutputTypeHandle(th, pXml->AddChild(MdaElemDecl(Type))); + AsMdaAssistant()->OutputException(pExceptionObj, pXml->AddChild(MdaElemDecl(Exception))); + + msg.SendMessagef(MDARC_EXCEPTION_SWALLOWED_COM_TO_CLR, + strMemberName.GetUnicode(), strTypeName.GetUnicode(), strMessage.GetUnicode()); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); +} + + +// +// MdaInvalidVariant +// +void MdaInvalidVariant::ReportViolation() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_INVALID_VARIANT); +} + + +// +// MdaInvalidIUnknown +// +void MdaInvalidIUnknown::ReportViolation() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_INVALID_IUNKNOWN); +} + + +// +// MdaContextSwitchDeadlock +// +void MdaContextSwitchDeadlock::ReportDeadlock(LPVOID Origin, LPVOID Destination) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + if (g_fEEShutDown == 0) + { + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_CONTEXT_SWITCH_DEADLOCK, Origin, Destination); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); + } +} + + +// +// MdaRaceOnRCWCleanup +// +void MdaRaceOnRCWCleanup::ReportViolation() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_RCW_CLEANUP_RACE); +} + + +// +// MdaFailedQI +// +void MdaFailedQI::ReportAdditionalInfo(HRESULT hr, RCW* pRCW, GUID iid, MethodTable* pMT) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + TypeHandle th(pMT); + + SafeComHolder<IUnknown> pInnerUnk = pRCW->GetIUnknown(); + + // We are interested in the case where the QI fails because of wrong context. + if (!pRCW->IsFreeThreaded() && GetCurrentCtxCookie() != pRCW->GetWrapperCtxCookie()) + { + // Try to change context and perform the QI in the new context again. + MdaFailedQIAssistantCallbackData data; + + data.pWrapper = pRCW; + data.iid = iid; + + pRCW->EnterContext(MdaFailedQIAssistantCallback, &data); + if (data.fSuccess) + { + // QI succeeds in the other context, i.e. the original QI fails because of wrong context. + pXml = AsMdaAssistant()->OutputTypeHandle(th, pXml->AddChild(MdaElemDecl(Type))); + + // Stringize IID + WCHAR strNativeItfIID[39]; + StringFromGUID2(iid, strNativeItfIID, sizeof(strNativeItfIID) / sizeof(WCHAR)); + + // Map HRESULT to a message + StackSString sszHR2Description; + GetHRMsg(hr, sszHR2Description); + + // Format the HRESULT as a string + StackSString sszHR2Hex; + sszHR2Hex.Printf("%.8x", hr); + + StackSString sszTypeName; + th.GetName(sszTypeName); + + msg.SendMessagef(MDARC_FAILED_QI, sszTypeName.GetUnicode(), strNativeItfIID, sszHR2Hex.GetUnicode(), sszHR2Description.GetUnicode()); + } + } + else if (hr == E_NOINTERFACE) + { + + // BUG: You'd have to check the registry to ensure that the proxy stub it's not actually there as opposed to the + // COM object QI simply returning a failure code. + + /* + // Check if pInnerUnk is actually pointing to a proxy, i.e. that it is pointing to an address + // within the loaded ole32.dll image. Note that WszGetModuleHandle does not increment the + // ref count. + HINSTANCE hModOle32 = WszGetModuleHandle(OLE32DLL); + if (hModOle32 && IsIPInModule(hModOle32, (BYTE *)(*(BYTE **)(IUnknown*)pInnerUnk))) + { + pXml = AsMdaAssistant()->OutputTypeHandle(th, pXml->AddChild(MdaElemDecl(Type))); + + WCHAR strGuid[40]; + GuidToLPWSTR(iid, strGuid, 40); + msg.SendMessagef(MDARC_FAILED_QI, strGuid); + } + */ + } +} + +HRESULT MdaFailedQIAssistantCallback(LPVOID pData) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_PREEMPTIVE; + SO_TOLERANT; + PRECONDITION(CheckPointer(pData)); + } + CONTRACTL_END; + + HRESULT hr = E_FAIL; + + BEGIN_EXTERNAL_ENTRYPOINT(&hr) + { + SafeComHolder<IUnknown> pDummyUnk; + + MdaFailedQIAssistantCallbackData *pCallbackData = (MdaFailedQIAssistantCallbackData *)pData; + + // Initialize the fSuccess flag to false until we know for a fact the QI will succeed. + pCallbackData->fSuccess = FALSE; + + // QI for the requested interface. + hr = pCallbackData->pWrapper->SafeQueryInterfaceRemoteAware(pCallbackData->iid, &pDummyUnk); + + // If the QI call succeded then set the fSuccess flag to true. + if (SUCCEEDED(hr)) + pCallbackData->fSuccess = TRUE; + } + END_EXTERNAL_ENTRYPOINT; + + return S_OK; // Need to return S_OK so that the assert in CtxEntry::EnterContext() won't fire. +} + +// +// MdaDisconnectedContext +// +void MdaDisconnectedContext::ReportViolationDisconnected(LPVOID context, HRESULT hr) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + if (g_fEEShutDown == 0) + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + StackSString strHRMsg; + GetHRMsg(hr, strHRMsg); + + msg.SendMessagef(MDARC_DISCONNECTED_CONTEXT_1, context, strHRMsg.GetUnicode()); + } +} + +void MdaDisconnectedContext::ReportViolationCleanup(LPVOID context1, LPVOID context2, HRESULT hr) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + if (g_fEEShutDown == 0) + { + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + StackSString strHRMsg; + GetHRMsg(hr, strHRMsg); + + msg.SendMessagef(MDARC_DISCONNECTED_CONTEXT_2, context1, strHRMsg.GetUnicode(), context2); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions) + } +} + + +// +// MdaInvalidApartmentStateChange +// +void MdaInvalidApartmentStateChange::ReportViolation(Thread* pThread, Thread::ApartmentState newstate, BOOL fAlreadySet) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + AsMdaAssistant()->OutputThread(pThread, pXml->AddChild(MdaElemDecl(Thread))); + + if (fAlreadySet) + { + if (newstate == Thread::AS_InSTA) + { + msg.SendMessagef(MDARC_INVALID_APT_STATE_CHANGE_SET, W("STA"), W("MTA")); + } + else + { + msg.SendMessagef(MDARC_INVALID_APT_STATE_CHANGE_SET, W("MTA"), W("STA")); + } + } + else + { + if (newstate == Thread::AS_InSTA) + { + msg.SendMessagef(MDARC_INVALID_APT_STATE_CHANGE_NOTSET, W("STA"), W("MTA")); + } + else + { + msg.SendMessagef(MDARC_INVALID_APT_STATE_CHANGE_NOTSET, W("MTA"), W("STA")); + } + } + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); +} + +// +// MdaDllMainReturnsFalse +// +void MdaDllMainReturnsFalse::ReportError() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END; + + BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return); + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_DLLMAIN_RETURNS_FALSE); + + END_SO_INTOLERANT_CODE; +} + +// +// MdaOverlappedFreeError +// +void MdaOverlappedFreeError::ReportError(LPVOID pOverlapped) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_INVALID_OVERLAPPED_FREE, + pOverlapped); +} + +// +// MdaInvalidOverlappedToPinvoke +// + +// NOTE: the overlapped pointer needs to be named "overlapped". +// It is embedded in the (Args) and (ArgsUsed) sections. + + +#define CREATE_WRAPPER_FUNCTION(DllName, Return, Flags, Name, Args, ArgsUsed) \ + DllName##_##Name, +enum { +#include "invalidoverlappedwrappers.h" +}; +#undef CREATE_WRAPPER_FUNCTION + +#define CREATE_WRAPPER_FUNCTION(DllName, Return, Flags, Name, Args, ArgsUsed) \ +Return Flags Mda_##Name Args \ +{ \ + CONTRACTL \ + { \ + THROWS; \ + GC_TRIGGERS; \ + SO_TOLERANT; \ + MODE_ANY; \ + } \ + CONTRACTL_END; \ + Return (Flags *old##Name) Args; \ + MdaInvalidOverlappedToPinvoke *pOverlapCheck = MDA_GET_ASSISTANT(InvalidOverlappedToPinvoke); \ + _ASSERTE(pOverlapCheck); \ + *(PVOID *)&(old##Name) = pOverlapCheck->CheckOverlappedPointer(DllName##_##Name, (LPVOID) overlapped); \ + return old##Name ArgsUsed; \ +} +#include "invalidoverlappedwrappers.h" +#undef CREATE_WRAPPER_FUNCTION + +#define CREATE_WRAPPER_FUNCTION(DllName, Return, Flags, Name, Args, ArgsUsed) \ + { L#DllName W(".DLL"), L#Name, Mda_##Name, NULL, NULL }, +static MdaInvalidOverlappedToPinvoke::pinvoke_entry PInvokeTable[] = { +#include "invalidoverlappedwrappers.h" +}; +#undef CREATE_WRAPPER_FUNCTION + +void MdaInvalidOverlappedToPinvoke::Initialize(MdaXmlElement* pXmlInput) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + +// TODO: CONTRACT_VIOLATION(SOToleranceViolation); + + m_entries = PInvokeTable; + m_entryCount = sizeof(PInvokeTable) / sizeof(pinvoke_entry); + m_bJustMyCode = pXmlInput->GetAttributeValueAsBool(MdaAttrDecl(JustMyCode)); +} + +BOOL MdaInvalidOverlappedToPinvoke::InitializeModuleFunctions(HINSTANCE hmod) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END; + + // For every entry where m_moduleName matches moduleName, fill in m_hmod with hmod + // and fill in the m_realFunction pointer. + + BOOL bFoundSomething = FALSE; + + BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return FALSE); + + SString moduleNameFullPath, moduleName; + ClrGetModuleFileNameNoThrow(hmod,moduleNameFullPath); + // Strip any path info + SString::CIterator iM = moduleNameFullPath.End(); + if (moduleNameFullPath.FindBack(iM, W('\\'))) + { + iM++; + moduleName.Set(moduleNameFullPath, iM, moduleNameFullPath.End()); + } + + for (UINT i=0; i<m_entryCount; i++) + { + if (SString::_wcsicmp(m_entries[i].m_moduleName, moduleName.GetUnicode()) == 0) + { + if (m_entries[i].m_hmod == NULL) + { + SString moduleNameForLookup(m_entries[i].m_functionName); + StackScratchBuffer ansiVersion; + m_entries[i].m_realFunction = GetProcAddress(hmod, moduleNameForLookup.GetANSI(ansiVersion)); + m_entries[i].m_hmod = hmod; + } + bFoundSomething = TRUE; + } + } + + END_SO_INTOLERANT_CODE; + + return bFoundSomething; +} + +LPVOID MdaInvalidOverlappedToPinvoke::CheckOverlappedPointer(UINT index, LPVOID pOverlapped) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END; + + MdaInvalidOverlappedToPinvoke::pinvoke_entry *pEntry = m_entries + index; + + // pEntry should always be non-NULL, because we got the address of pvMdaFunction + // from the entries table in the first place. + _ASSERTE(pEntry); + if (pEntry == NULL) + { + return NULL; + } + + // Is the overlapped pointer in the gc heap? + if (pOverlapped != NULL) + { + // If a stack overflow occurs, we would just want to continue and + // return the function pointer as expected. + BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return pEntry->m_realFunction); + + BOOL fHeapPointer; + + { + GCX_COOP(); + GCHeap *pHeap = GCHeap::GetGCHeap(); + fHeapPointer = pHeap->IsHeapPointer(pOverlapped); + } + + if (!fHeapPointer) + { + // Output a message + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_INVALID_OVERLAPPED_TO_PINVOKE, + pOverlapped, + pEntry->m_functionName, + pEntry->m_moduleName); + } + + END_SO_INTOLERANT_CODE; + } + + return pEntry->m_realFunction; +} + +// We want to hook the functions where it is in the user's code only, unless +// the attribute JustMyCode is set to false. In that case, we want all +// occurances. +BOOL MdaInvalidOverlappedToPinvoke::ShouldHook(MethodDesc *pMD) +{ + LIMITED_METHOD_CONTRACT; + return (m_bJustMyCode ? IsJustMyCode(pMD) : TRUE); +} + +LPVOID MdaInvalidOverlappedToPinvoke::Register(HINSTANCE hmod,LPVOID pvTarget) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END; + + // Quick lookup - do we have a matching target? + // walk our entries, looking for a match. + BOOL bNullModules = FALSE; + BOOL bSeenThisModule = FALSE; + + for (UINT i=0; i<m_entryCount; i++) + { + MdaInvalidOverlappedToPinvoke::pinvoke_entry *pEntry = m_entries + i; + if (pvTarget == pEntry->m_realFunction) + { + return pEntry->m_mdaFunction; + } + + bNullModules |= (pEntry->m_hmod == NULL); + bSeenThisModule |= (pEntry->m_hmod == hmod); + } + + // if we have some NULL targets, do we have a matching hmod? + // if so, + if (bNullModules && !bSeenThisModule) + { + if (InitializeModuleFunctions(hmod)) + { + // Search once more + for (UINT i=0; i<m_entryCount; i++) + { + pinvoke_entry *pEntry = m_entries + i; + if (pvTarget == pEntry->m_realFunction) + { + return pEntry->m_mdaFunction; + } + } + } + } + + return NULL; +} + +// +// MdaPInvokeLog +// +BOOL MdaPInvokeLog::Filter(SString& sszDllName) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXmlFilter = m_pXmlInput->GetChild(MdaElemDecl(Filter)); + if (!pXmlFilter) + return TRUE; + + BOOL bFound = FALSE; + for (COUNT_T i = 0; i < pXmlFilter->GetChildren().GetCount(); i ++) + { + if (pXmlFilter->GetChildren()[i]->GetAttribute(MdaAttrDecl(DllName))->GetValueAsCSString()->EqualsCaseInsensitive(sszDllName)) + { + bFound = TRUE; + break; + } + } + + return bFound; +} + +void MdaPInvokeLog::LogPInvoke(NDirectMethodDesc* pMD, HINSTANCE hMod) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + StackSString sszEntryPoint; + sszEntryPoint.SetUTF8(pMD->GetEntrypointName()); + + PathString szDllFullName ; + WCHAR szDrive[_MAX_PATH] = {0}; + WCHAR szPath[_MAX_PATH] = {0}; + WCHAR szFileName[_MAX_PATH] = {0}; + WCHAR szExt[_MAX_PATH] = {0}; + WszGetModuleFileName(hMod, szDllFullName); + SplitPath(szDllFullName, szDrive, _MAX_PATH, szPath, _MAX_PATH, szFileName, _MAX_PATH, szExt, _MAX_PATH); + + StackSString sszDllName; + sszDllName.Append(szFileName); + if (szExt) + sszDllName.Append(szExt); + + if (Filter(sszDllName)) + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), FALSE, &pXml); + + MdaXmlElement* pMethod = pXml->AddChild(MdaElemDecl(Method)); + AsMdaAssistant()->OutputMethodDesc(pMD, pMethod); + + MdaXmlElement* pDllImport = pXml->AddChild(MdaElemDecl(DllImport)); + pDllImport->AddAttributeSz(MdaAttrDecl(DllName), szDllFullName); + pDllImport->AddAttributeSz(MdaAttrDecl(EntryPoint), sszEntryPoint.GetUnicode()); + + msg.SendMessage(); + } + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); +} + + +#ifdef _TARGET_X86_ +// +// MdaPInvokeStackImbalance +// +void MdaPInvokeStackImbalance::CheckStack(StackImbalanceCookie *pSICookie, DWORD dwPostEsp) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END; + + DWORD dwEspAfterPushedArgs = pSICookie->m_dwSavedEsp; + DWORD dwEspBeforePushedArgs = dwEspAfterPushedArgs + pSICookie->m_dwStackArgSize; + BOOL bStackImbalance = false; + + // Note: We use relaxed rules here depending on the NetFx40_PInvokeStackResilience compat switch in order to mimic 2.0 behavior. + switch (pSICookie->m_callConv & pmCallConvMask) + { + // Caller cleans stack + case pmCallConvCdecl: + if (dwPostEsp != dwEspAfterPushedArgs) + { + if (dwPostEsp != dwEspBeforePushedArgs) + { + bStackImbalance = true; + } + else + { + // If NetFx40_PInvokeStackResilience is on, ignore the case where we see that the callee cleaned the stack. + BOOL fPreV4Method = pSICookie->m_pMD->GetModule()->IsPreV4Assembly(); + if (!g_pConfig->PInvokeRestoreEsp(fPreV4Method)) + bStackImbalance = true; + } + } + break; + + // Callee cleans stack + case pmCallConvThiscall: + case pmCallConvWinapi: + case pmCallConvStdcall: + if (dwPostEsp != dwEspBeforePushedArgs) + { + if (dwPostEsp != dwEspAfterPushedArgs) + { + bStackImbalance = true; + } + else + { + // If NetFx40_PInvokeStackResilience is on, ignore the case where we see that the callee did not clean the stack + BOOL fPreV4Method = pSICookie->m_pMD->GetModule()->IsPreV4Assembly(); + if (!g_pConfig->PInvokeRestoreEsp(fPreV4Method)) + bStackImbalance = true; + } + } + break; + + // Unsupported calling convention + case pmCallConvFastcall: + default: + _ASSERTE(!"Unsupported calling convention"); + break; + } + + if (!bStackImbalance) + return; + + BEGIN_SO_INTOLERANT_CODE(GetThread()); + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + MdaXmlElement* pMethod = pXml->AddChild(MdaElemDecl(Method)); + AsMdaAssistant()->OutputMethodDesc(pSICookie->m_pMD, pMethod); + + StackSString sszMethodName; + msg.SendMessagef(MDARC_PINVOKE_SIGNATURE_MISMATCH, AsMdaAssistant()->ToString(sszMethodName, pSICookie->m_pMD).GetUnicode()); + + END_SO_INTOLERANT_CODE; +} +#endif + + +// +// MdaJitCompilationStart +// +void MdaJitCompilationStart::Initialize(MdaXmlElement* pXmlInput) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + m_bBreak = pXmlInput->GetAttributeValueAsBool(MdaAttrDecl(Break)); + MdaXmlElement* pXmlMethodFilter = pXmlInput->GetChild(MdaElemDecl(Methods)); + m_pMethodFilter = NULL; + + if (pXmlMethodFilter) + { + m_pMethodFilter = new MdaQuery::CompiledQueries(); + MdaQuery::Compile(pXmlMethodFilter, m_pMethodFilter); + } +} + +void MdaJitCompilationStart::NowCompiling(MethodDesc* pMD) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + if (m_pMethodFilter && !m_pMethodFilter->Test(pMD)) + return; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), m_bBreak, &pXml); + + MdaXmlElement* pMethod = pXml->AddChild(MdaElemDecl(Method)); + AsMdaAssistant()->OutputMethodDesc(pMD, pMethod); + + msg.SendMessage(); +} + +// +// MdaLoadFromContext +// +void MdaLoadFromContext::NowLoading(IAssembly** ppIAssembly, StackCrawlMark *pCallerStackMark) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + if (ppIAssembly && *ppIAssembly) { + + // Send an MDA if this assembly was loaded in the LoadFrom context + if ((*ppIAssembly)->GetFusionLoadContext() == LOADCTX_TYPE_LOADFROM) { + // Apply MDA filtering + if (g_pDebugInterface && pCallerStackMark && ManagedDebuggingAssistants::IsManagedDebuggerAttached()) { + MethodDesc *pMethodDesc = NULL; + { + GCX_COOP(); + pMethodDesc = SystemDomain::GetCallersMethod(pCallerStackMark, NULL); + } + if (pMethodDesc && !g_pDebugInterface->IsJMCMethod(pMethodDesc->GetModule(), pMethodDesc->GetMemberDef())) + return; + } + + MdaXmlElement *pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + MdaXmlElement *pXmlAssembly = pXml->AddChild(MdaElemDecl(AssemblyInfo)); + + StackSString sszAssemblyName; + StackSString sszCodeBase; + SafeComHolder<IAssemblyName> pNameDef; + + if (FAILED((*ppIAssembly)->GetAssemblyNameDef(&pNameDef))) { + return; + } + + if ((!FusionBind::GetAssemblyNameStringProperty(pNameDef, ASM_NAME_NAME, sszAssemblyName)) || + (!FusionBind::GetAssemblyNameStringProperty(pNameDef, ASM_NAME_CODEBASE_URL, sszCodeBase))) { + return; + } + + pXmlAssembly->AddAttributeSz(MdaAttrDecl(DisplayName), sszAssemblyName.GetUnicode()); + pXmlAssembly->AddAttributeSz(MdaAttrDecl(CodeBase), sszCodeBase.GetUnicode()); + + msg.SendMessagef(MDARC_LOAD_FROM_CONTEXT, sszAssemblyName.GetUnicode(), sszCodeBase.GetUnicode()); + } + } +} + +const LPCWSTR ContextIdName[] = +{ + W("Load"), + W("LoadFrom"), + W("Anonymous") +}; + +// +// MdaBindingFailure +// +void MdaBindingFailure::BindFailed(AssemblySpec *pSpec, OBJECTREF *pExceptionObj) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement *pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + MdaXmlElement *pXmlAssembly = pXml->AddChild(MdaElemDecl(AssemblyInfo)); + + DWORD dwAppDomainId; + SString sszAssemblyName; + SString sszCodeBase; + SString sszMessage; + int iBindingContext; + HRESULT hr; + + // determine AppDomain ID + AppDomain *appDomain = pSpec->GetAppDomain(); + if (appDomain) { + dwAppDomainId = appDomain->GetId().m_dwId; + } else { + dwAppDomainId = 0; + } + pXmlAssembly->AddAttributeInt(MdaAttrDecl(AppDomainId), dwAppDomainId); + + // determine Assembly display name + LPCSTR assemblyName = pSpec->GetName(); + if (assemblyName && assemblyName[0]) { + sszAssemblyName.SetASCII(assemblyName); + } + pXmlAssembly->AddAttributeSz(MdaAttrDecl(DisplayName), sszAssemblyName.GetUnicode()); + + // determine Assembly code base + if (pSpec->GetCodeBase() && pSpec->GetCodeBase()[0]) { + sszCodeBase.Set(pSpec->GetCodeBase()); + } + pXmlAssembly->AddAttributeSz(MdaAttrDecl(CodeBase), sszCodeBase.GetUnicode()); + + // retrieve the exception message. + GetExceptionMessage(*pExceptionObj, sszMessage); + + // determine failing HRESULT + hr = GetExceptionHResult(*pExceptionObj); + pXmlAssembly->AddAttributeInt(MdaAttrDecl(HResult), hr); + + // determine binding context Assembly would have been loaded in (based on parent) + IAssembly* pParentAssembly = pSpec->GetParentIAssembly(); + if (pParentAssembly) { + iBindingContext = pParentAssembly->GetFusionLoadContext(); + } else { + + // if the parent hasn't been set but the code base has, it's in LoadFrom + iBindingContext = LOADCTX_TYPE_LOADFROM; + } + pXmlAssembly->AddAttributeInt(MdaAttrDecl(BindingContextId), iBindingContext); + + // Make sure the binding context ID isn't larger then our ID to name lookup table. + _ASSERTE(iBindingContext < COUNTOF(ContextIdName)); + + if (sszAssemblyName.IsEmpty()) + { + _ASSERTE(!sszCodeBase.IsEmpty()); + msg.SendMessagef(MDARC_BINDING_FAILURE_CODEBASE_ONLY, sszCodeBase.GetUnicode(), + ContextIdName[iBindingContext], dwAppDomainId, sszMessage.GetUnicode()); + } + else if (sszCodeBase.IsEmpty()) + { + _ASSERTE(!sszAssemblyName.IsEmpty()); + msg.SendMessagef(MDARC_BINDING_FAILURE_DISPLAYNAME_ONLY, sszAssemblyName.GetUnicode(), + ContextIdName[iBindingContext], dwAppDomainId, sszMessage.GetUnicode()); + } + else + { + msg.SendMessagef(MDARC_BINDING_FAILURE, sszAssemblyName.GetUnicode(), sszCodeBase.GetUnicode(), + ContextIdName[iBindingContext], dwAppDomainId, sszMessage.GetUnicode()); + } +} + + +// +// MdaReflection +// +FCIMPL0(void, MdaManagedSupport::MemberInfoCacheCreation) +{ + FCALL_CONTRACT; + + HELPER_METHOD_FRAME_BEGIN_0(); + { + MdaMemberInfoCacheCreation* pMda = MDA_GET_ASSISTANT(MemberInfoCacheCreation); + if (pMda) + { + pMda->MemberInfoCacheCreation(); + } + } + HELPER_METHOD_FRAME_END(); +} +FCIMPLEND + +void MdaMemberInfoCacheCreation::MemberInfoCacheCreation() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessage(MDARC_REFLECTION_PERFORMANCE_MEMBERINFOCACHECREATION); +} + + +FCIMPL0(FC_BOOL_RET, MdaManagedSupport::IsStreamWriterBufferedDataLostEnabled) +{ + FCALL_CONTRACT; + + // To see if it's enabled, allocate one then throw it away. + MdaStreamWriterBufferedDataLost* pMda = MDA_GET_ASSISTANT(StreamWriterBufferedDataLost); + + FC_RETURN_BOOL(pMda != NULL); +} +FCIMPLEND + +FCIMPL0(FC_BOOL_RET, MdaManagedSupport::IsStreamWriterBufferedDataLostCaptureAllocatedCallStack) +{ + FCALL_CONTRACT; + + // To see if it's enabled, allocate one then throw it away. + MdaStreamWriterBufferedDataLost* pMda = MDA_GET_ASSISTANT(StreamWriterBufferedDataLost); + + FC_RETURN_BOOL((pMda != NULL) && (pMda->CaptureAllocatedCallStack())); +} +FCIMPLEND + +FCIMPL1(void, MdaManagedSupport::ReportStreamWriterBufferedDataLost, StringObject * stringRef) +{ + FCALL_CONTRACT; + + STRINGREF str(stringRef); + MdaStreamWriterBufferedDataLost* pMda = MDA_GET_ASSISTANT(StreamWriterBufferedDataLost); + if (pMda) + { + HELPER_METHOD_FRAME_BEGIN_1(str); + StackSString message(str->GetBuffer()); + pMda->ReportError(message); + HELPER_METHOD_FRAME_END(); + } +} +FCIMPLEND + +FCIMPL0(FC_BOOL_RET, MdaManagedSupport::IsInvalidGCHandleCookieProbeEnabled) +{ + FCALL_CONTRACT; + + // To see if it's enabled, allocate one then throw it away. + MdaInvalidGCHandleCookie* pMda = MDA_GET_ASSISTANT(InvalidGCHandleCookie); + + FC_RETURN_BOOL(pMda != NULL); +} +FCIMPLEND + +FCIMPL1(void, MdaManagedSupport::FireInvalidGCHandleCookieProbe, LPVOID cookie) +{ + FCALL_CONTRACT; + + MdaInvalidGCHandleCookie* pMda = MDA_GET_ASSISTANT(InvalidGCHandleCookie); + if (pMda) + { + HELPER_METHOD_FRAME_BEGIN_0(); + pMda->ReportError(cookie); + HELPER_METHOD_FRAME_END(); + } +} +FCIMPLEND + +FCIMPL1(void, MdaManagedSupport::ReportErrorSafeHandleRelease, ExceptionObject * exceptionRef) +{ + FCALL_CONTRACT; + + OBJECTREF exception(exceptionRef); + MdaMarshalCleanupError* pMda = MDA_GET_ASSISTANT(MarshalCleanupError); + if (pMda) + { + HELPER_METHOD_FRAME_BEGIN_1(exception); + pMda->ReportErrorSafeHandleRelease(&exception); + HELPER_METHOD_FRAME_END(); + } +} +FCIMPLEND + +void MdaInvalidGCHandleCookie::ReportError(LPVOID cookie) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_INVALID_GCHANDLE_COOKIE, cookie); +} + +void MdaStreamWriterBufferedDataLost::ReportError(SString text) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessage(text); +} + + +// +// MdaNotMarshalable +// +void MdaNotMarshalable::ReportViolation() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_NOTMARSHALABLE); +} + + +// +// MdaMarshalCleanupError +// +void MdaMarshalCleanupError::ReportErrorThreadCulture(OBJECTREF *pExceptionObj) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + // retrieve the exception message. + SString sszMessage; + GetExceptionMessage(*pExceptionObj, sszMessage); + + msg.SendMessagef(MDARC_MARSHALCLEANUPERROR_THREADCULTURE, sszMessage.GetUnicode()); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); +} + +void MdaMarshalCleanupError::ReportErrorSafeHandleRelease(OBJECTREF *pExceptionObj) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + // retrieve the exception message. + SString sszMessage; + GetExceptionMessage(*pExceptionObj, sszMessage); + + msg.SendMessagef(MDARC_MARSHALCLEANUPERROR_SAFEHANDLERELEASE, sszMessage.GetUnicode()); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); +} + +void MdaMarshalCleanupError::ReportErrorSafeHandleProp(OBJECTREF *pExceptionObj) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + // retrieve the exception message. + SString sszMessage; + GetExceptionMessage(*pExceptionObj, sszMessage); + + msg.SendMessagef(MDARC_MARSHALCLEANUPERROR_SAFEHANDLEPROP, sszMessage.GetUnicode()); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); +} + +void MdaMarshalCleanupError::ReportErrorCustomMarshalerCleanup(TypeHandle typeCustomMarshaler, OBJECTREF *pExceptionObj) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + // retrieve the exception message. + SString sszMessage; + GetExceptionMessage(*pExceptionObj, sszMessage); + + // Retrieve the type name. + StackSString sszType; + typeCustomMarshaler.GetName(sszType); + + msg.SendMessagef(MDARC_MARSHALCLEANUPERROR_CUSTOMCLEANUP, sszType.GetUnicode(), sszMessage.GetUnicode()); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); +} + +// +// MdaMarshaling +// +void MdaMarshaling::Initialize(MdaXmlElement* pXmlInput) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + m_pMethodFilter = new MdaQuery::CompiledQueries(); + m_pFieldFilter = new MdaQuery::CompiledQueries(); + + MdaXmlElement* pXmlMethodFilter = pXmlInput->GetChild(MdaElemDecl(MethodFilter)); + if (pXmlMethodFilter) + MdaQuery::Compile(pXmlMethodFilter, m_pMethodFilter); + + MdaXmlElement* pXmlFieldFilter = pXmlInput->GetChild(MdaElemDecl(FieldFilter)); + if (pXmlFieldFilter) + MdaQuery::Compile(pXmlFieldFilter, m_pFieldFilter); +} + +void MdaMarshaling::ReportFieldMarshal(FieldMarshaler* pFM) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + PRECONDITION(CheckPointer(pFM)); + } + CONTRACTL_END; + + FieldDesc* pFD = pFM->GetFieldDesc(); + + if (!pFD || !m_pFieldFilter->Test(pFD)) + return; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), FALSE, &pXml); + + MdaXmlElement* pField = pXml->AddChild(MdaElemDecl(MarshalingField)); + AsMdaAssistant()->OutputFieldDesc(pFD, pField); + + StackSString sszField; + SString managed; + SString unmanaged; + + GetManagedSideForField(managed, pFD); + GetUnmanagedSideForField(unmanaged, pFM); + + msg.SendMessagef(MDARC_MARSHALING_FIELD, AsMdaAssistant()->ToString(sszField, pFD).GetUnicode(), managed.GetUnicode(), unmanaged.GetUnicode()); +} + + +void MdaMarshaling::GetManagedSideForField(SString& strManagedMarshalType, FieldDesc* pFD) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + if (!CheckForPrimitiveType(pFD->GetFieldType(), strManagedMarshalType)) + { + // The following workaround is added to avoid a recursion caused by calling GetTypeHandle on + // the m_value field of the UIntPtr class. + LPCUTF8 szNamespace, szClassName; + IfFailThrow(pFD->GetMDImport()->GetNameOfTypeDef(pFD->GetApproxEnclosingMethodTable()->GetCl(), &szClassName, &szNamespace)); + + if (strcmp(szNamespace, "System") == 0 && strcmp(szClassName, "UIntPtr") == 0) + { + static LPWSTR strRetVal = W("Void*"); + strManagedMarshalType.Set(strRetVal); + } + else + { + MetaSig fSig(pFD); + fSig.NextArgNormalized(); + TypeHandle th = fSig.GetLastTypeHandleNT(); + if (th.IsNull()) + { + static const WCHAR strErrorMsg[] = W("<error>"); + strManagedMarshalType.Set(strErrorMsg); + } + else + { + SigFormat sigFmt; + sigFmt.AddType(th); + UINT iManagedTypeLen = (UINT)strlen(sigFmt.GetCString()) + 1; + + WCHAR* buffer = strManagedMarshalType.OpenUnicodeBuffer(iManagedTypeLen); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sigFmt.GetCString(), -1, buffer, iManagedTypeLen); + strManagedMarshalType.CloseBuffer(); + } + } + } +} + +void MdaMarshaling::GetUnmanagedSideForField(SString& strUnmanagedMarshalType, FieldMarshaler* pFM) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + NStructFieldTypeToString(pFM, strUnmanagedMarshalType); +} + + +void MdaMarshaling::GetManagedSideForMethod(SString& strManagedMarshalType, Module* pModule, SigPointer sig, CorElementType elemType) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + if (!CheckForPrimitiveType(elemType, strManagedMarshalType)) + { + // an empty type context is sufficient: all methods should be non-generic + SigTypeContext emptyTypeContext; + + TypeHandle th = sig.GetTypeHandleNT(pModule, &emptyTypeContext); + if (th.IsNull()) + { + strManagedMarshalType.Set(W("<error>")); + } + else + { + SigFormat sigfmt; + sigfmt.AddType(th); + UINT iManagedMarshalTypeLength = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, sigfmt.GetCString(), -1, NULL, 0); + + WCHAR* str = strManagedMarshalType.OpenUnicodeBuffer(iManagedMarshalTypeLength); + MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, sigfmt.GetCString(), -1, str, iManagedMarshalTypeLength); + strManagedMarshalType.CloseBuffer(); + } + } +} + + +void MdaMarshaling::GetUnmanagedSideForMethod(SString& strNativeMarshalType, MarshalInfo* mi, BOOL fSizeIsSpecified) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + mi->MarshalTypeToString(strNativeMarshalType, fSizeIsSpecified); +} + +BOOL MdaMarshaling::CheckForPrimitiveType(CorElementType elemType, SString& strPrimitiveType) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + SO_INTOLERANT; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END; + + LPWSTR strRetVal; + + switch (elemType) + { + case ELEMENT_TYPE_VOID: + strRetVal = W("Void"); + break; + case ELEMENT_TYPE_BOOLEAN: + strRetVal = W("Boolean"); + break; + case ELEMENT_TYPE_I1: + strRetVal = W("SByte"); + break; + case ELEMENT_TYPE_U1: + strRetVal = W("Byte"); + break; + case ELEMENT_TYPE_I2: + strRetVal = W("Int16"); + break; + case ELEMENT_TYPE_U2: + strRetVal = W("UInt16"); + break; + case ELEMENT_TYPE_CHAR: + strRetVal = W("Char"); + break; + case ELEMENT_TYPE_I: + strRetVal = W("IntPtr"); + break; + case ELEMENT_TYPE_U: + strRetVal = W("UIntPtr"); + break; + case ELEMENT_TYPE_I4: + strRetVal = W("Int32"); + break; + case ELEMENT_TYPE_U4: + strRetVal = W("UInt32"); + break; + case ELEMENT_TYPE_I8: + strRetVal = W("Int64"); + break; + case ELEMENT_TYPE_U8: + strRetVal = W("UInt64"); + break; + case ELEMENT_TYPE_R4: + strRetVal = W("Single"); + break; + case ELEMENT_TYPE_R8: + strRetVal = W("Double"); + break; + default: + return FALSE; + } + + strPrimitiveType.Set(strRetVal); + return TRUE; +} + +// +// MdaLoaderLock +// +void MdaLoaderLock::ReportViolation(HINSTANCE hInst) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + // Called from SO_TOLERANT CODE + SO_TOLERANT; + } + CONTRACTL_END; + + BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return); + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + DWORD cName = 0; + PathString szName; + if (hInst) + { + cName = WszGetModuleFileName(hInst, szName); + } + + if (cName) + { + msg.SendMessagef(MDARC_LOADER_LOCK_DLL, szName); + } + else + { + msg.SendMessagef(MDARC_LOADER_LOCK); + } + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); + + END_SO_INTOLERANT_CODE; +} + + +// +// MdaReentrancy +// +void MdaReentrancy::ReportViolation() +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END; + + BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return); + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_REENTRANCY); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); + + END_SO_INTOLERANT_CODE; +} + +// +// MdaAsynchronousThreadAbort +// +void MdaAsynchronousThreadAbort::ReportViolation(Thread *pCallingThread, Thread *pAbortedThread) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + AsMdaAssistant()->OutputThread(pCallingThread, pXml->AddChild(MdaElemDecl(CallingThread))); + AsMdaAssistant()->OutputThread(pAbortedThread, pXml->AddChild(MdaElemDecl(AbortedThread))); + + msg.SendMessagef(MDARC_ASYNCHRONOUS_THREADABORT, pCallingThread->GetOSThreadId(), pAbortedThread->GetOSThreadId()); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); +} + + +// +// MdaAsynchronousThreadAbort +// +void MdaDangerousThreadingAPI::ReportViolation(__in_z WCHAR *apiName) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_DANGEROUS_THREADINGAPI, apiName); +} + + +// +// MdaReportAvOnComRelease +// + +void MdaReportAvOnComRelease::ReportHandledException(RCW* pRCW) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + FAULT_NOT_FATAL(); + + // TODO: comment this code... + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + if (pRCW) + { + LPVOID vtablePtr = pRCW->GetVTablePtr(); + msg.SendMessagef(MDARC_REPORT_AV_ON_COM_RELEASE_WITH_VTABLE, vtablePtr); + } + else + { + msg.SendMessagef(MDARC_REPORT_AV_ON_COM_RELEASE); + } + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); +} + +void MdaInvalidFunctionPointerInDelegate::ReportViolation(LPVOID pFunc) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_INVALID_FUNCTION_PTR_IN_DELEGATE, pFunc); +} + +// +// MdaDirtyCastAndCallOnInterface +// + +void MdaDirtyCastAndCallOnInterface::ReportViolation(IUnknown* pUnk) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_DIRTY_CAST_AND_CALL_ON_INTERFACE); +} + +// +// MdaFatalExecutionEngineError +// +void MdaFatalExecutionEngineError::ReportFEEE(TADDR addrOfError, HRESULT hrError) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + EX_TRY + { + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + DWORD tid = GetCurrentThreadId(); + + msg.SendMessagef(MDARC_FATAL_EXECUTION_ENGINE_ERROR, addrOfError, tid, hrError); + } + EX_CATCH + { + // Caller cannot take exceptions. + } + EX_END_CATCH(SwallowAllExceptions); +} + + +// +// MdaInvalidCERCall +// +void MdaInvalidCERCall::ReportViolation(MethodDesc* pCallerMD, MethodDesc *pCalleeMD, DWORD dwOffset) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), FALSE, &pXml); + + AsMdaAssistant()->OutputMethodDesc(pCalleeMD, pXml->AddChild(MdaElemDecl(Method))); + AsMdaAssistant()->OutputCallsite(pCallerMD, dwOffset, pXml->AddChild(MdaElemDecl(Callsite))); + + StackSString sszCalleeMethodName(SString::Utf8, pCalleeMD->GetName()); + StackSString sszCallerMethodName(SString::Utf8, pCallerMD->GetName()); + msg.SendMessagef(MDARC_INVALID_CER_CALL, sszCallerMethodName.GetUnicode(), dwOffset, sszCalleeMethodName.GetUnicode()); +} + + +// +// MdaVirtualCERCall +// +void MdaVirtualCERCall::ReportViolation(MethodDesc* pCallerMD, MethodDesc *pCalleeMD, DWORD dwOffset) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), FALSE, &pXml); + + AsMdaAssistant()->OutputMethodDesc(pCalleeMD, pXml->AddChild(MdaElemDecl(Method))); + AsMdaAssistant()->OutputCallsite(pCallerMD, dwOffset, pXml->AddChild(MdaElemDecl(Callsite))); + + StackSString sszCalleeMethodName(SString::Utf8, pCalleeMD->GetName()); + StackSString sszCallerMethodName(SString::Utf8, pCallerMD->GetName()); + msg.SendMessagef(MDARC_VIRTUAL_CER_CALL, sszCallerMethodName.GetUnicode(), dwOffset, sszCalleeMethodName.GetUnicode()); +} + + +// +// MdaOpenGenericCERCall +// +void MdaOpenGenericCERCall::ReportViolation(MethodDesc* pMD) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), FALSE, &pXml); + + AsMdaAssistant()->OutputMethodDesc(pMD, pXml->AddChild(MdaElemDecl(Method))); + + StackSString sszMethodName(SString::Utf8, pMD->GetName()); + msg.SendMessagef(MDARC_OPENGENERIC_CER_CALL, sszMethodName.GetUnicode()); +} + + +// +// MdaIllegalPrepareConstrainedRegion +// +void MdaIllegalPrepareConstrainedRegion::ReportViolation(MethodDesc* pMD, DWORD dwOffset) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), FALSE, &pXml); + + AsMdaAssistant()->OutputCallsite(pMD, dwOffset, pXml->AddChild(MdaElemDecl(Callsite))); + + StackSString sszMethodName(SString::Utf8, pMD->GetName()); + msg.SendMessagef(MDARC_ILLEGAL_PCR, sszMethodName.GetUnicode(), dwOffset); +} + + +// +// MdaReleaseHandleFailed +// +void MdaReleaseHandleFailed::ReportViolation(TypeHandle th, LPVOID lpvHandle) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + AsMdaAssistant()->OutputTypeHandle(th, pXml->AddChild(MdaElemDecl(Type))); + + StackSString sszHandle; + sszHandle.Printf(W("0x%p"), lpvHandle); + pXml->AddChild(MdaElemDecl(Handle))->AddAttributeSz(MdaAttrDecl(Value), sszHandle.GetUnicode()); + + StackSString sszType; + th.GetName(sszType); + msg.SendMessagef(MDARC_SAFEHANDLE_CRITICAL_FAILURE, sszType.GetUnicode(), lpvHandle); +} + + +#ifdef FEATURE_COMINTEROP +// +// MdaReleaseHandleFailed +// +void MdaNonComVisibleBaseClass::ReportViolation(MethodTable *pMT, BOOL fForIDispatch) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + TypeHandle thDerived = TypeHandle(pMT); + TypeHandle thBase = thDerived.GetParent(); + + while (IsTypeVisibleFromCom(thBase)) + thBase = thBase.GetParent(); + + // If we get there, one of the parents must be non COM visible. + _ASSERTE(!thBase.IsNull()); + + AsMdaAssistant()->OutputTypeHandle(thDerived, pXml->AddChild(MdaElemDecl(DerivedType))); + AsMdaAssistant()->OutputTypeHandle(thBase, pXml->AddChild(MdaElemDecl(BaseType))); + + SString strDerivedClassName; + SString strBaseClassName; + + thDerived.GetName(strDerivedClassName); + thBase.GetName(strBaseClassName); + + + msg.SendMessagef(fForIDispatch ? MDARC_NON_COMVISIBLE_BASE_CLASS_IDISPATCH : MDARC_NON_COMVISIBLE_BASE_CLASS_CLASSITF, + strDerivedClassName.GetUnicode(), strBaseClassName.GetUnicode()); +} +#endif //FEATURE_COMINTEROP + + +#ifdef _DEBUG +// +// MdaXmlValidationError +// +void MdaXmlValidationError::ReportError(MdaSchema::ValidationResult* pValidationResult) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + DEBUG_ONLY; + SO_NOT_MAINLINE; + } + CONTRACTL_END; + PRECONDITION(CheckPointer(pValidationResult->m_pViolatingElement)); + PRECONDITION(CheckPointer(pValidationResult->m_pViolatedElement)); + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), FALSE, &pXml); + + pXml->AddChild(MdaElemDecl(ViolatingXml))->AddChild(pValidationResult->m_pXmlRoot); + pValidationResult->m_pSchema->ToXml(pXml->AddChild(MdaElemDecl(ViolatedXsd))); + + msg.SendMessage(W("The following XML does not match its schema.")); +} +#endif + + +// +// InvalidConfigFile +// +void MdaInvalidConfigFile::ReportError(MdaElemDeclDef configFile) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + DEBUG_ONLY; + SO_NOT_MAINLINE; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage report(this->AsMdaAssistant(), TRUE, &pXml); + + LPCWSTR szConfigFile = MdaSchema::GetElementName(configFile); + pXml->AddAttributeSz(MdaAttrDecl(ConfigFile), szConfigFile); + + report.SendMessagef(MDARC_INVALID_CONFIG_FILE, szConfigFile); +} + +// +// MdaDateTimeInvalidLocalFormat +// +void MdaDateTimeInvalidLocalFormat::ReportError() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + DEBUG_ONLY; + SO_NOT_MAINLINE; + } + CONTRACTL_END; + + MdaXmlElement* pXml; + MdaXmlMessage msg(this->AsMdaAssistant(), TRUE, &pXml); + + msg.SendMessagef(MDARC_DATETIME_INVALID_LOCAL_FORMAT); +} + +FCIMPL0(void, MdaManagedSupport::DateTimeInvalidLocalFormat) +{ + FCALL_CONTRACT; + + MdaDateTimeInvalidLocalFormat* pMda = MDA_GET_ASSISTANT(DateTimeInvalidLocalFormat); + if (pMda) + { + HELPER_METHOD_FRAME_BEGIN_0(); + pMda->ReportError(); + HELPER_METHOD_FRAME_END(); + } +} +FCIMPLEND + +#endif +#endif //MDA_SUPPORTED |