summaryrefslogtreecommitdiff
path: root/src/vm/newcompressedstack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/newcompressedstack.cpp')
-rw-r--r--src/vm/newcompressedstack.cpp1074
1 files changed, 1074 insertions, 0 deletions
diff --git a/src/vm/newcompressedstack.cpp b/src/vm/newcompressedstack.cpp
new file mode 100644
index 0000000000..5957dc37f4
--- /dev/null
+++ b/src/vm/newcompressedstack.cpp
@@ -0,0 +1,1074 @@
+// 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 FEATURE_COMPRESSEDSTACK
+
+#include "newcompressedstack.h"
+#include "security.h"
+#ifdef FEATURE_REMOTING
+#include "appdomainhelper.h"
+#endif
+#include "securitystackwalk.h"
+#include "appdomainstack.inl"
+#include "appdomain.inl"
+
+
+DomainCompressedStack::DomainCompressedStack(ADID domainID)
+: m_DomainID(domainID),
+ m_ignoreAD(FALSE),
+ m_dwOverridesCount(0),
+ m_dwAssertCount(0),
+ m_Homogeneous(FALSE)
+{
+ WRAPPER_NO_CONTRACT;
+}
+
+BOOL DomainCompressedStack::IsAssemblyPresent(ISharedSecurityDescriptor* ssd)
+{
+ CONTRACTL
+ {
+ MODE_ANY;
+ GC_NOTRIGGER;
+ NOTHROW;
+ }CONTRACTL_END;
+
+
+ // Only checks the first level and does not recurse into compressed stacks
+ void* pEntry = NULL;
+
+ if (m_EntryList.GetCount() == 0)
+ return FALSE;
+
+ // Quick check the last entry we added - common case
+ pEntry = m_EntryList.Get(m_EntryList.GetCount() - 1);
+ if (pEntry == (void *)SET_LOW_BIT(ssd))
+ return TRUE;
+
+ // Go thru the whole list now - is this optimal?
+ ArrayList::Iterator iter = m_EntryList.Iterate();
+
+ while (iter.Next())
+ {
+ pEntry = iter.GetElement();
+ if (pEntry == (void *)SET_LOW_BIT(ssd))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void DomainCompressedStack::AddEntry(void * ptr)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ IfFailThrow(m_EntryList.Append(ptr));
+
+}
+VOID FrameSecurityDescriptorCopyFrom(FRAMESECDESCREF newFsdRef, FRAMESECDESCREF fsd)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+ newFsdRef->SetImperativeAssertions(fsd->GetImperativeAssertions());
+ newFsdRef->SetImperativeDenials(fsd->GetImperativeDenials());
+ newFsdRef->SetImperativeRestrictions(fsd->GetImperativeRestrictions());
+ newFsdRef->SetDeclarativeAssertions(fsd->GetDeclarativeAssertions());
+ newFsdRef->SetDeclarativeDenials(fsd->GetDeclarativeDenials());
+ newFsdRef->SetDeclarativeRestrictions(fsd->GetDeclarativeRestrictions());
+ newFsdRef->SetAssertAllPossible(fsd->HasAssertAllPossible());
+ newFsdRef->SetAssertFT(fsd->HasAssertFT());
+}
+
+void DomainCompressedStack::AddFrameEntry(AppDomain *pAppDomain, FRAMESECDESCREF fsdRef, BOOL bIsAHDMFrame, OBJECTREF dynamicResolverRef)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ ENTER_DOMAIN_PTR(pAppDomain,ADV_RUNNINGIN) //have it on the stack
+ {
+ struct gc
+ {
+ OBJECTREF fsdRef;
+ OBJECTREF newFsdRef;
+ OBJECTREF dynamicResolverRef;
+ } gc;
+ ZeroMemory( &gc, sizeof( gc ) );
+ gc.fsdRef = (OBJECTREF)fsdRef;
+ gc.dynamicResolverRef = dynamicResolverRef;
+
+ GCPROTECT_BEGIN(gc);
+
+ static MethodTable* pMethFrameSecDesc = NULL;
+ if (pMethFrameSecDesc == NULL)
+ pMethFrameSecDesc = MscorlibBinder::GetClass(CLASS__FRAME_SECURITY_DESCRIPTOR);
+
+ static MethodTable* pMethFrameSecDescWCS = NULL;
+ if (pMethFrameSecDescWCS == NULL)
+ pMethFrameSecDescWCS = MscorlibBinder::GetClass(CLASS__FRAME_SECURITY_DESCRIPTOR_WITH_RESOLVER);
+
+ if(!bIsAHDMFrame)
+ {
+ gc.newFsdRef = AllocateObject(pMethFrameSecDesc);
+ }
+ else
+ {
+ gc.newFsdRef = AllocateObject(pMethFrameSecDescWCS);
+ }
+
+ // We will not call the ctor and instead patch up the object based on the fsdRef passed in
+ FRAMESECDESCREF newFsdRef = (FRAMESECDESCREF)gc.newFsdRef;
+ FRAMESECDESCREF fsdRef1 = (FRAMESECDESCREF)gc.fsdRef;
+ if(fsdRef1 != NULL)
+ {
+ FrameSecurityDescriptorCopyFrom(newFsdRef, fsdRef1);
+ }
+ if(bIsAHDMFrame)
+ {
+ _ASSERTE(gc.dynamicResolverRef != NULL);
+ ((FRAMESECDESWITHRESOLVERCREF)newFsdRef)->SetDynamicMethodResolver(gc.dynamicResolverRef);
+ }
+ OBJECTHANDLEHolder tmpHnd(pAppDomain->CreateHandle(gc.newFsdRef));
+
+ AddEntry((void*)tmpHnd);
+ tmpHnd.SuppressRelease();
+ GCPROTECT_END();
+
+ }
+ END_DOMAIN_TRANSITION;
+
+}
+
+
+void DomainCompressedStack::Destroy(void)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Clear Domain info (handles etc.) if the AD has not been unloaded.
+ ClearDomainInfo();
+ return;
+}
+
+FCIMPL1(DWORD, DomainCompressedStack::GetDescCount, DomainCompressedStack* dcs)
+{
+ FCALL_CONTRACT;
+
+ FCUnique(0x42);
+
+ return dcs->m_EntryList.GetCount();
+}
+FCIMPLEND
+
+FCIMPL3(void, DomainCompressedStack::GetDomainPermissionSets, DomainCompressedStack* dcs, OBJECTREF* ppGranted, OBJECTREF* ppDenied)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ *ppGranted = NULL;
+ *ppDenied = NULL;
+
+ AppDomain* appDomain = SystemDomain::GetAppDomainFromId(dcs->GetMyDomain(),ADV_RUNNINGIN);
+ if (appDomain == NULL)
+ {
+ // this might be the unloading AD
+ AppDomain *pUnloadingDomain = SystemDomain::System()->AppDomainBeingUnloaded();
+ if (pUnloadingDomain && pUnloadingDomain->GetId() == dcs->m_DomainID)
+ {
+#ifdef _DEBUG
+ CheckADValidity(pUnloadingDomain, ADV_RUNNINGIN);
+#endif
+ appDomain = pUnloadingDomain;
+ }
+ }
+ _ASSERTE(appDomain != NULL);
+ if (appDomain != NULL)
+ {
+ IApplicationSecurityDescriptor * pAppSecDesc = appDomain->GetSecurityDescriptor();
+ _ASSERTE(pAppSecDesc != NULL);
+ if (pAppSecDesc != NULL)
+ {
+ *ppGranted = pAppSecDesc->GetGrantedPermissionSet(ppDenied);
+ }
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL6(FC_BOOL_RET, DomainCompressedStack::GetDescriptorInfo, DomainCompressedStack* dcs, DWORD index, OBJECTREF* ppGranted, OBJECTREF* ppDenied, OBJECTREF* ppAssembly, OBJECTREF* ppFSD)
+{
+ FCALL_CONTRACT;
+
+ _ASSERTE(dcs != NULL);
+ AppDomain* pCurrentDomain = GetAppDomain();
+ BOOL bRetVal = FALSE;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_0()
+ *ppGranted = NULL;
+ *ppDenied = NULL;
+ *ppAssembly = NULL;
+ *ppFSD = NULL;
+ void* pEntry = dcs->m_EntryList.Get(index);
+ _ASSERTE(pEntry != NULL);
+ if (IS_LOW_BIT_SET(pEntry))
+ {
+ // Assembly found
+ SharedSecurityDescriptor* pSharedSecDesc = (SharedSecurityDescriptor* )UNSET_LOW_BIT(pEntry);
+ Assembly* pAssembly = pSharedSecDesc->GetAssembly();
+ IAssemblySecurityDescriptor* pAsmSecDesc = pAssembly->GetSecurityDescriptor( pCurrentDomain );
+ *ppGranted = pAsmSecDesc->GetGrantedPermissionSet(ppDenied);
+ *ppAssembly = pAssembly->GetExposedObject();
+ }
+ else
+ {
+ //FSD
+ OBJECTHANDLE objHnd = (OBJECTHANDLE)pEntry;
+ if (objHnd == NULL)
+ {
+ // throw an ADUnloaded exception which we will catch and then look at the serializedBlob
+ COMPlusThrow(kAppDomainUnloadedException);
+ }
+ *ppFSD = ObjectFromHandle(objHnd);
+ bRetVal = TRUE;
+ }
+ HELPER_METHOD_FRAME_END();
+
+ FC_RETURN_BOOL(bRetVal);
+}
+FCIMPLEND
+
+FCIMPL1(FC_BOOL_RET, DomainCompressedStack::IgnoreDomain, DomainCompressedStack* dcs)
+{
+ FCALL_CONTRACT;
+
+ _ASSERTE(dcs != NULL);
+
+ FC_RETURN_BOOL(dcs->IgnoreDomainInternal());
+}
+FCIMPLEND
+
+BOOL DomainCompressedStack::IgnoreDomainInternal()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ if (m_ignoreAD)
+ return TRUE;
+
+ AppDomainFromIDHolder appDomain(GetMyDomain(), TRUE);
+ if (!appDomain.IsUnloaded())
+ {
+ IApplicationSecurityDescriptor *pAppSecDesc = appDomain->GetSecurityDescriptor();
+ _ASSERTE(pAppSecDesc != NULL);
+ if (pAppSecDesc != NULL)
+ {
+ return pAppSecDesc->IsDefaultAppDomain() || pAppSecDesc->IsInitializationInProgress();
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*
+ Note that this function is called only once: when the managed PLS is being created.
+ It's possible that 2 threads could race at that point: only downside of that is that they will both do the work. No races.
+ Also, we'll never be operating on a DCS whose domain is not on the current callstack. This eliminates all kinds of ADU/demand eval races.
+*/
+OBJECTREF DomainCompressedStack::GetDomainCompressedStackInternal(AppDomain *pDomain)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ // If we are going to skip this AppDomain, and there is nothing to compress, then we can skip building the DCS.
+ if (m_EntryList.GetCount() == 0 && IgnoreDomainInternal())
+ return NULL;
+
+ AppDomain* pCurrentDomain = GetAppDomain();
+
+ NewArrayHolder<BYTE> pbtmpSerializedObject(NULL);
+#ifndef FEATURE_CORECLR
+ DWORD cbtmpSerializedObject = 0;
+#endif
+
+ struct gc
+ {
+ OBJECTREF refRetVal;
+ } gc;
+ ZeroMemory( &gc, sizeof( gc ) );
+
+ GCPROTECT_BEGIN( gc );
+
+ // Create object
+ ENTER_DOMAIN_ID (GetMyDomain()) //on the stack
+ {
+
+ // Go ahead and create the object
+#ifdef FEATURE_CORECLR // ignore other appdomains
+ if (GetAppDomain() == pCurrentDomain)
+#endif
+ {
+ MethodDescCallSite createManagedObject(METHOD__DOMAIN_COMPRESSED_STACK__CREATE_MANAGED_OBJECT);
+ ARG_SLOT args[] = {PtrToArgSlot(this)};
+ gc.refRetVal = createManagedObject.Call_RetOBJECTREF(args);
+ }
+
+#ifndef FEATURE_CORECLR
+ // Do we want to marshal this object also?
+ if (GetAppDomain() != pCurrentDomain)
+ {
+ // Serialize to a blob;
+ AppDomainHelper::MarshalObject(GetAppDomain(), &gc.refRetVal, &pbtmpSerializedObject, &cbtmpSerializedObject);
+ if (pbtmpSerializedObject == NULL)
+ {
+ // this is an error: possibly an OOM prevented the blob from getting created.
+ // We could return null and let the managed code use a fully restricted object or throw here.
+ // Let's throw here...
+ COMPlusThrow(kSecurityException);
+ }
+ }
+#endif
+
+ }
+ END_DOMAIN_TRANSITION
+
+#ifndef FEATURE_CORECLR // should never happen for core clr
+ if (GetMyDomain() != pCurrentDomain->GetId())
+ {
+ AppDomainHelper::UnmarshalObject(pCurrentDomain,pbtmpSerializedObject, cbtmpSerializedObject, &gc.refRetVal);
+ }
+#endif
+
+ GCPROTECT_END();
+
+ return gc.refRetVal;
+}
+
+
+void DomainCompressedStack::ClearDomainInfo(void)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+
+ // So, assume mutual exclusion holds and no races occur here
+
+
+ // Now it is time to go NULL out any ObjectHandle we're using in the list of entries
+ ArrayList::Iterator iter = m_EntryList.Iterate();
+
+ while (iter.Next())
+ {
+ void* pEntry = iter.GetElement();
+ if (!IS_LOW_BIT_SET(pEntry))
+ {
+ DestroyHandle((OBJECTHANDLE)pEntry);
+ }
+ pEntry = NULL;
+ }
+
+
+ // Always clear the index into the domain object list and the domainID.
+ m_DomainID = ADID(INVALID_APPDOMAIN_ID);
+ return;
+}
+
+NewCompressedStack::NewCompressedStack()
+: m_DCSListCount(0),
+ m_currentDCS(NULL),
+ m_pCtxTxFrame(NULL),
+ m_CSAD(ADID(INVALID_APPDOMAIN_ID)),
+ m_ADStack(GetThread()->GetAppDomainStack()),
+ m_dwOverridesCount(0),
+ m_dwAssertCount(0)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(m_ADStack.GetNumDomains() > 0);
+ m_ADStack.InitDomainIteration(&adStackIndex);
+ m_DCSList = new DomainCompressedStack*[m_ADStack.GetNumDomains()];
+ memset(m_DCSList, 0, (m_ADStack.GetNumDomains()*sizeof(DomainCompressedStack*)));
+
+}
+
+
+void NewCompressedStack::Destroy( CLR_BOOL bEntriesOnly )
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (m_DCSList != NULL)
+ {
+ m_currentDCS = NULL;
+ m_pCtxTxFrame = NULL;
+ for (DWORD i=0; i< m_ADStack.GetNumDomains(); i++)
+ {
+ DomainCompressedStack* dcs = m_DCSList[i];
+ if (dcs != NULL)
+ {
+ dcs->Destroy();
+ delete dcs;
+ }
+ }
+ delete[] m_DCSList;
+ m_DCSList = NULL;
+ }
+ if (!bEntriesOnly)
+ delete this;
+
+}
+
+
+void NewCompressedStack::ProcessAppDomainTransition(void)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ } CONTRACTL_END;
+
+ // Get the current adstack entry. Note that the first time we enter this function, adStackIndex will
+ // equal the size of the adstack array (similar to what happens in IEnumerator).
+ // So the initial pEntry will be NULL
+ AppDomainStackEntry *pEntry =
+ (adStackIndex == m_ADStack.GetNumDomains() ? NULL : m_ADStack.GetCurrentDomainEntryOnStack(adStackIndex));
+
+ // Updated the value on the ADStack for current domain
+ if (pEntry != NULL)
+ {
+ DWORD domainOverrides_measured = (m_currentDCS == NULL?0:m_currentDCS->GetOverridesCount());
+ DWORD domainAsserts_measured = (m_currentDCS == NULL?0:m_currentDCS->GetAssertCount());
+ if (pEntry->m_dwOverridesCount != domainOverrides_measured || pEntry->m_dwAsserts != domainAsserts_measured)
+ {
+ m_ADStack.UpdateDomainOnStack(adStackIndex, domainAsserts_measured, domainOverrides_measured);
+ GetThread()->UpdateDomainOnStack(adStackIndex, domainAsserts_measured, domainOverrides_measured);
+ }
+ }
+
+ // Move the domain index forward if this is not the last entry
+ if (adStackIndex > 0)
+ m_ADStack.GetNextDomainEntryOnStack(&adStackIndex);
+ m_currentDCS = NULL;
+
+ return;
+
+}
+DWORD NewCompressedStack::ProcessFrame(AppDomain* pAppDomain, Assembly* pAssembly, MethodDesc* pFunc, ISharedSecurityDescriptor* pSsd, FRAMESECDESCREF* pFsdRef)
+{
+ // This function will be called each time we hit a new stack frame in a stack walk.
+
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pAppDomain));
+ PRECONDITION(CheckPointer(pSsd));
+ } CONTRACTL_END;
+
+ // Get the current adstack entry. Note that the first time we enter this function, adStackIndex will
+ // equal the size of the adstack array (similar to what happens in IEnumerator).
+ // So the initial pEntry will be NULL
+ AppDomainStackEntry *pEntry =
+ (adStackIndex == m_ADStack.GetNumDomains() ? NULL : m_ADStack.GetCurrentDomainEntryOnStack(adStackIndex));
+
+
+ _ASSERTE(pEntry != NULL);
+ PREFIX_ASSUME(pEntry != NULL);
+ FRAMESECDESCREF FsdRef = (pFsdRef!=NULL?*pFsdRef:NULL);
+ DWORD dwFlags = 0;
+ if (FsdRef != NULL)
+ {
+
+ if (FsdRef->HasAssertFT())
+ dwFlags |= CORSEC_FT_ASSERT;
+ }
+
+ BOOL bIsAHDMFrame = FALSE;
+
+ if((pFunc != NULL) && !CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_Security_DisableAnonymouslyHostedDynamicMethodCreatorSecurityCheck))
+ {
+ ENTER_DOMAIN_PTR(pAppDomain, ADV_RUNNINGIN)
+ {
+ bIsAHDMFrame = SecurityStackWalk::MethodIsAnonymouslyHostedDynamicMethodWithCSToEvaluate(pFunc);
+ }
+ END_DOMAIN_TRANSITION;
+ }
+
+ if (!bIsAHDMFrame && ((pEntry->IsFullyTrustedWithNoStackModifiers()) ||
+ (m_currentDCS != NULL && m_currentDCS->m_Homogeneous)))
+ {
+ // Nothing to do in this entire AD.
+ return dwFlags;
+ }
+
+ ADID dNewDomainID = pAppDomain->GetId();
+ BOOL bAddSSD = (!pSsd->IsSystem() && !IsAssemblyPresent(dNewDomainID, pSsd));
+ BOOL bHasStackModifiers = FALSE;
+ DWORD overridesCount = 0;
+ DWORD assertCount = 0;
+
+
+ if (FsdRef != NULL)
+ {
+ overridesCount += FsdRef->GetOverridesCount();
+ assertCount += FsdRef->GetAssertCount();
+ }
+
+ // If this is an AHDM frame with a CS to evaluate, it may have overrides or asserts,
+ // so treat it as if it does
+ if(bIsAHDMFrame)
+ {
+ overridesCount++;
+ assertCount++;
+ }
+
+ bHasStackModifiers = ( (assertCount + overridesCount) > 0);
+
+ //
+ // We need to add a new DCS if we don't already have one for this AppDomain. If we've reached this
+ // point, either:
+ // * the AppDomain is partially trusted
+ // * the AppDomain is fully trusted, but may have stack modifiers in play
+ // * we're running in legacy mode where FullTrust doesn't mean FullTrust
+ //
+ // If the domain is partially trusted, we'll always need to capture it. If we got this far due to a
+ // fully trusted domain that might have stack modifiers, we only have to capture if there really were
+ // stack walk modifiers. In the legacy mode case, we need to capture the domain if we had stack
+ // modifiers or we needed to add the shared security descriptor.
+ //
+
+ BOOL bCreateDCS = (m_currentDCS == NULL || m_currentDCS->m_DomainID != dNewDomainID);
+ if (pAppDomain->GetSecurityDescriptor()->IsFullyTrusted())
+ {
+ bCreateDCS &= (bAddSSD || bHasStackModifiers);
+ }
+
+ if (bCreateDCS)
+ {
+ CreateDCS(dNewDomainID);
+ }
+
+ // Add the ISharedSecurityDescriptor (Assembly) to the list if it is not already present in the list
+ if (bAddSSD)
+ {
+ m_currentDCS->AddEntry((void*)SET_LOW_BIT(pSsd));
+ if (pEntry->IsHomogeneousWithNoStackModifiers())
+ m_currentDCS->m_Homogeneous = TRUE;
+ }
+ if (bHasStackModifiers)
+ {
+ OBJECTREF dynamicResolverRef = NULL;
+ if(bIsAHDMFrame)
+ {
+ _ASSERTE(pFunc->IsLCGMethod());
+ dynamicResolverRef = pFunc->AsDynamicMethodDesc()->GetLCGMethodResolver()->GetManagedResolver();
+ }
+
+ // We need to add the FSD entry here
+ m_currentDCS->AddFrameEntry(pAppDomain, FsdRef, bIsAHDMFrame, dynamicResolverRef);
+ m_currentDCS->m_dwOverridesCount += overridesCount;
+ m_currentDCS->m_dwAssertCount += assertCount;
+ m_dwOverridesCount += overridesCount;
+ m_dwAssertCount += assertCount;
+ }
+ return dwFlags;
+}
+
+// Build a CompressedStack given that all domains on the stack are homogeneous with no stack modifiers
+FCIMPL1(void, NewCompressedStack::FCallGetHomogeneousPLS, Object* hgPLSUnsafe)
+{
+ FCALL_CONTRACT;
+
+ OBJECTREF refHomogeneousPLS = (OBJECTREF)hgPLSUnsafe;
+
+ HELPER_METHOD_FRAME_BEGIN_1(refHomogeneousPLS);
+
+
+ // Walk the adstack and update the grantSetUnion
+ AppDomainStack* pADStack = GetThread()->GetAppDomainStackPointer();
+ DWORD dwAppDomainIndex;
+ pADStack->InitDomainIteration(&dwAppDomainIndex);
+
+#ifdef FEATURE_REMOTING // without remoting we need only current appdomain
+ while (dwAppDomainIndex != 0)
+#endif
+ {
+ AppDomainStackEntry* pEntry = pADStack->GetNextDomainEntryOnStack(&dwAppDomainIndex);
+ _ASSERTE(pEntry != NULL);
+
+ pEntry->UpdateHomogeneousPLS(&refHomogeneousPLS);
+ }
+
+
+ HELPER_METHOD_FRAME_END();
+ return ;
+}
+FCIMPLEND;
+
+// Special case of ProcessFrame called with the CS at the base of the thread
+void NewCompressedStack::ProcessCS(AppDomain* pAppDomain, COMPRESSEDSTACKREF csRef, Frame *pFrame)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pAppDomain));
+ } CONTRACTL_END;
+
+ _ASSERTE(csRef != NULL && "Shouldn't call this function if CS is NULL");
+ ADID dNewDomainID = pAppDomain->GetId();
+ NewCompressedStack* pCS = (NewCompressedStack* )csRef->GetUnmanagedCompressedStack();
+ if (csRef->IsEmptyPLS() && (pCS == NULL || pCS->GetDCSListCount() == 0))
+ {
+ // Do nothing - empty inner CS
+ return;
+ }
+
+ // Let's special case the 1-domain CS that has no inner CSs here
+ // Check for:
+ // 1. == 1 DCS
+ // 2. DCS is in correct AD (it's possible that pCS is AD-X and it has only one DCS in AD-Y, because AD-X has only mscorlib frames
+ // 3. No inner CS
+ if ( pCS != NULL &&
+ pCS->GetDCSListCount() == 1 &&
+ pCS->m_DCSList != NULL &&
+ pCS->m_currentDCS != NULL &&
+ pCS->m_currentDCS->m_DomainID == dNewDomainID &&
+ pCS->m_CSAD == ADID(INVALID_APPDOMAIN_ID))
+ {
+ ProcessSingleDomainNCS(pCS, pAppDomain);
+ }
+ else
+ {
+
+ // set flag to ignore Domain grant set if the current DCS is the same as the one with the CS
+ if (m_currentDCS != NULL && m_currentDCS->m_DomainID == dNewDomainID)
+ {
+ m_currentDCS->m_ignoreAD = TRUE;
+ }
+
+ // Update overrides/asserts
+ if (pCS != NULL)
+ {
+ m_dwOverridesCount += pCS->GetOverridesCount();
+ m_dwAssertCount += pCS->GetAssertCount();
+ }
+
+
+ // Do we need to store the CtxTransitionFrame or did we get the CS from the thread?
+ if (pFrame != NULL)
+ {
+ _ASSERTE(csRef == SecurityStackWalk::GetCSFromContextTransitionFrame(pFrame));
+ // Use data from the CtxTxFrame
+ m_pCtxTxFrame = pFrame;
+ }
+ m_CSAD = dNewDomainID;
+ }
+
+}
+void NewCompressedStack::ProcessSingleDomainNCS(NewCompressedStack *pCS, AppDomain* pAppDomain)
+{
+
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pAppDomain));
+ } CONTRACTL_END;
+
+ _ASSERTE(pCS->GetDCSListCount() <= 1 && pCS->m_CSAD == ADID(INVALID_APPDOMAIN_ID));
+ ADID newDomainID = pAppDomain->GetId();
+ DomainCompressedStack* otherDCS = pCS->m_currentDCS;
+
+ if (otherDCS == NULL)
+ return;
+ if (m_currentDCS == NULL)
+ CreateDCS(newDomainID);
+
+
+ // Iterate thru the entryList in the current DCS
+ ArrayList::Iterator iter = otherDCS->m_EntryList.Iterate();
+ while (iter.Next())
+ {
+ void* pEntry = iter.GetElement();
+ if (IS_LOW_BIT_SET(pEntry))
+ {
+ if (!IsAssemblyPresent(newDomainID, (ISharedSecurityDescriptor*)UNSET_LOW_BIT(pEntry)))
+ {
+ //Add the assembly
+ m_currentDCS->AddEntry(pEntry);
+ }
+ }
+ else
+ {
+ // FrameSecurityDescriptor
+ OBJECTHANDLE objHnd = (OBJECTHANDLE)pEntry;
+ OBJECTREF fsdRef = ObjectFromHandle(objHnd);
+ OBJECTHANDLEHolder tmpHnd(pAppDomain->CreateHandle(fsdRef));
+
+ m_currentDCS->AddEntry((void*)tmpHnd);
+ tmpHnd.SuppressRelease();
+
+ }
+
+ }
+
+ m_currentDCS->m_dwOverridesCount += pCS->m_dwOverridesCount;
+ m_currentDCS->m_dwAssertCount += pCS->m_dwAssertCount;
+ m_dwOverridesCount += pCS->m_dwOverridesCount;
+ m_dwAssertCount += pCS->m_dwAssertCount;
+}
+void NewCompressedStack::CreateDCS(ADID domainID)
+{
+ CONTRACTL {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(adStackIndex < m_ADStack.GetNumDomains());
+ _ASSERTE (m_DCSList != NULL);
+ m_DCSList[adStackIndex] = new DomainCompressedStack(domainID);
+ m_currentDCS = m_DCSList[adStackIndex];
+ m_DCSListCount++;
+
+ return;
+}
+
+
+BOOL NewCompressedStack::IsAssemblyPresent(ADID domainID, ISharedSecurityDescriptor* pSsd)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(domainID != ADID(INVALID_APPDOMAIN_ID) && "Don't pass invalid domain");
+
+ BOOL bEntryPresent = FALSE;
+
+ for(DWORD i=0; i < m_ADStack.GetNumDomains(); i++)
+ {
+
+ DomainCompressedStack* pTmpDCS = m_DCSList[i];
+
+ if (pTmpDCS != NULL && pTmpDCS->m_DomainID == domainID && pTmpDCS->IsAssemblyPresent(pSsd))
+ {
+ bEntryPresent = TRUE;
+ break;
+ }
+ }
+ return bEntryPresent;
+}
+
+
+BOOL NewCompressedStack::IsDCSContained(DomainCompressedStack *pDCS)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // return FALSE if no DCS or DCS is for a domain that has been unloaded
+ if (pDCS == NULL || pDCS->m_DomainID == ADID(INVALID_APPDOMAIN_ID))
+ return FALSE;
+
+
+
+ // Iterate thru the entryList in the current DCS
+ ArrayList::Iterator iter = pDCS->m_EntryList.Iterate();
+ while (iter.Next())
+ {
+ void* pEntry = iter.GetElement();
+ if (IS_LOW_BIT_SET(pEntry))
+ {
+ // We only check Assemblies.
+ if (!IsAssemblyPresent(pDCS->m_DomainID, (ISharedSecurityDescriptor*)UNSET_LOW_BIT(pEntry)))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOL NewCompressedStack::IsNCSContained(NewCompressedStack *pCS)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Check if the first level of pCS is contained in this.
+ if (pCS == NULL)
+ return TRUE;
+
+ // Return FALSE if there are any overrides or asserts
+ if (pCS->GetOverridesCount() > 0)
+ return FALSE;
+ // Return FALSE if there is an inner CS
+ if (pCS->m_CSAD != ADID(INVALID_APPDOMAIN_ID))
+ return FALSE;
+
+ for(DWORD i=0; i < m_ADStack.GetNumDomains(); i++)
+ {
+ DomainCompressedStack *pDCS = (DomainCompressedStack *) m_DCSList[i];
+ if (!IsDCSContained(pDCS))
+ return FALSE;
+ }
+ return TRUE;
+
+}
+
+
+// If there is a compressed stack present in the captured CompressedStack, return that CS in the current domain
+OBJECTREF NewCompressedStack::GetCompressedStackInner()
+{
+ _ASSERTE(m_CSAD != ADID(INVALID_APPDOMAIN_ID));
+
+ AppDomain* pCurrentDomain = GetAppDomain();
+ NewArrayHolder<BYTE> pbtmpSerializedObject(NULL);
+
+
+ OBJECTREF refRetVal = NULL;
+
+ if (pCurrentDomain->GetId()== m_CSAD)
+ {
+ // we're in the right domain already
+ if (m_pCtxTxFrame == NULL)
+ {
+ // Get CS from the thread
+ refRetVal = GetThread()->GetCompressedStack();
+ }
+ else
+ {
+ // Get CS from a Ctx transition frame
+ refRetVal = (OBJECTREF)SecurityStackWalk::GetCSFromContextTransitionFrame(m_pCtxTxFrame);
+ _ASSERTE(refRetVal != NULL); //otherwise we would not have saved the frame in the CB data
+ }
+ }
+ else
+#ifndef FEATURE_CORECLR // should never happen for core clr
+ {
+ DWORD cbtmpSerializedObject = 0;
+ GCPROTECT_BEGIN (refRetVal);
+ // need to marshal the CS over into the current AD
+ ENTER_DOMAIN_ID(m_CSAD);
+ {
+ if (m_pCtxTxFrame == NULL)
+ {
+
+ // Get CS from the thread
+ refRetVal = GetThread()->GetCompressedStack();
+ }
+ else
+ {
+ // Get CS from a Ctx transition frame
+ refRetVal = (OBJECTREF)SecurityStackWalk::GetCSFromContextTransitionFrame(m_pCtxTxFrame);
+ _ASSERTE(refRetVal != NULL); //otherwise we would not have saved the frame in the CB data
+ }
+ AppDomainHelper::MarshalObject(GetAppDomain(), &refRetVal, &pbtmpSerializedObject, &cbtmpSerializedObject);
+ }
+ END_DOMAIN_TRANSITION
+ refRetVal = NULL;
+ AppDomainHelper::UnmarshalObject(pCurrentDomain,pbtmpSerializedObject, cbtmpSerializedObject, &refRetVal);
+ GCPROTECT_END ();
+ _ASSERTE(refRetVal != NULL); //otherwise we would not have saved the frame in the CB data
+ }
+#else
+ {
+ UNREACHABLE();
+ }
+#endif // !FEATURE_CORECLR
+
+ return refRetVal;
+
+}
+
+// == Now begin the functions used in building Demand evaluation of a compressed stack
+FCIMPL1(DWORD, NewCompressedStack::FCallGetDCSCount, SafeHandle* hcsUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ DWORD dwRet = 0;
+ if (hcsUNSAFE != NULL)
+ {
+ SAFEHANDLE hcsSAFE = (SAFEHANDLE) hcsUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_1(hcsSAFE);
+
+ NewCompressedStack* ncs = (NewCompressedStack *)hcsSAFE->GetHandle();
+
+ dwRet = ncs->m_ADStack.GetNumDomains();
+ HELPER_METHOD_FRAME_END();
+ }
+
+ return dwRet;
+
+}
+FCIMPLEND
+
+
+FCIMPL2(FC_BOOL_RET, NewCompressedStack::FCallIsImmediateCompletionCandidate, SafeHandle* hcsUNSAFE, OBJECTREF *innerCS)
+{
+ FCALL_CONTRACT;
+
+ BOOL bRet = FALSE;
+ if (hcsUNSAFE != NULL)
+ {
+ SAFEHANDLE hcsSAFE = (SAFEHANDLE) hcsUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_1(hcsSAFE);
+
+ *innerCS = NULL;
+
+ NewCompressedStack* ncs = (NewCompressedStack *)hcsSAFE->GetHandle();
+
+ if (ncs != NULL)
+ {
+ // Non-FT case
+
+ // Is there an inner CS?
+ BOOL bHasCS = (ncs->m_CSAD != ADID(INVALID_APPDOMAIN_ID));
+
+ // Is there is a DCS not in the current AD
+ BOOL bHasOtherAppDomain = FALSE;
+ if (ncs->m_DCSList != NULL)
+ {
+ for(DWORD i=0; i < ncs->m_ADStack.GetNumDomains(); i++)
+ {
+ DomainCompressedStack* dcs = ncs->m_DCSList[i];
+ if (dcs != NULL && dcs->GetMyDomain() != GetAppDomain()->GetId())
+ {
+ bHasOtherAppDomain = TRUE;
+ break;
+ }
+ }
+ }
+ if (bHasCS)
+ {
+
+
+ *innerCS = ncs->GetCompressedStackInner();
+ ncs->m_pCtxTxFrame = NULL; // Clear the CtxTxFrame ASAP
+
+ }
+ bRet = bHasOtherAppDomain||bHasCS;
+ }
+
+ HELPER_METHOD_FRAME_END();
+ }
+
+ FC_RETURN_BOOL(bRet);
+}
+FCIMPLEND
+
+
+FCIMPL2(Object*, NewCompressedStack::GetDomainCompressedStack, SafeHandle* hcsUNSAFE, DWORD index)
+{
+ FCALL_CONTRACT;
+
+ OBJECTREF refRetVal = NULL;
+ if (hcsUNSAFE != NULL)
+ {
+ SAFEHANDLE hcsSAFE = (SAFEHANDLE) hcsUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_2(refRetVal, hcsSAFE);
+
+
+
+ NewCompressedStack* ncs = (NewCompressedStack *)hcsSAFE->GetHandle();
+
+ // First we check to see if the DCS at index i has a blob. If so, deserialize it into the current AD and return it. Else try create it
+ DomainCompressedStack* dcs = ncs->m_DCSList[index];
+ if (dcs != NULL)
+ {
+ refRetVal = dcs->GetDomainCompressedStackInternal(NULL);
+ }
+
+ HELPER_METHOD_FRAME_END();
+ }
+
+ return OBJECTREFToObject(refRetVal);
+
+}
+FCIMPLEND
+
+FCIMPL1(void, NewCompressedStack::DestroyDCSList, SafeHandle* hcsUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ SAFEHANDLE hcsSAFE = (SAFEHANDLE) hcsUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_1(hcsSAFE);
+
+ NewCompressedStack* ncs = (NewCompressedStack *)hcsSAFE->GetHandle();
+
+ ncs->Destroy(TRUE);
+
+ HELPER_METHOD_FRAME_END();
+
+}
+FCIMPLEND
+#endif // #ifdef FEATURE_COMPRESSEDSTACK