// ==++==
//
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
// Appdomainstack.h -
//
//
#ifndef __appdomainstack_h__
#define __appdomainstack_h__
#include "vars.hpp"
#include "util.hpp"
// Stack of AppDomains executing on the current thread. Used in security optimization to avoid stackwalks
#define ADSTACK_BLOCK_SIZE 16
#define INVALID_APPDOMAIN_ID ((DWORD)-1)
#define CURRENT_APPDOMAIN_ID ((ADID)(DWORD)0)
#define __GetADID(index) ((index)<ADSTACK_BLOCK_SIZE?m_pStack[(index)].m_domainID:m_pExtraStack[((index)-ADSTACK_BLOCK_SIZE)].m_domainID)
#define __GetEntryPtr(index) ((index)<ADSTACK_BLOCK_SIZE?&(m_pStack[(index)]):&(m_pExtraStack[((index)-ADSTACK_BLOCK_SIZE)]))
struct AppDomainStackEntry
{
ADID m_domainID;
DWORD m_dwOverridesCount;
DWORD m_dwAsserts;
DWORD m_dwPreviousThreadWideSpecialFlags;
FORCEINLINE bool operator==(const AppDomainStackEntry& entry) const
{
return (m_domainID == entry.m_domainID &&
m_dwOverridesCount == entry.m_dwOverridesCount &&
m_dwAsserts == entry.m_dwAsserts);
}
FORCEINLINE bool operator!=(const AppDomainStackEntry& entry) const
{
return (m_domainID != entry.m_domainID ||
m_dwOverridesCount != entry.m_dwOverridesCount ||
m_dwAsserts != entry.m_dwAsserts);
}
BOOL IsFullyTrustedWithNoStackModifiers(void);
BOOL IsHomogeneousWithNoStackModifiers(void);
BOOL HasFlagsOrFullyTrustedWithNoStackModifiers(DWORD flags);
#ifndef DACCESS_COMPILE
void UpdateHomogeneousPLS(OBJECTREF* homogeneousPLS);
#endif
};
class AppDomainStack
{
public:
AppDomainStack() : m_numEntries(0), m_pExtraStack(NULL), m_ExtraStackSize(0), m_dwOverridesCount(0), m_dwAsserts(0), m_dwThreadWideSpecialFlags(0xFFFFFFFF)
{
WRAPPER_CONTRACT;
FillEntries(m_pStack, ADSTACK_BLOCK_SIZE);
}
AppDomainStack(const AppDomainStack& stack):m_numEntries(0), m_pExtraStack(NULL), m_ExtraStackSize(0), m_dwOverridesCount(0), m_dwAsserts(0)
{
CONTRACTL {
THROWS;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
m_dwThreadWideSpecialFlags = stack.m_dwThreadWideSpecialFlags;
m_numEntries = stack.m_numEntries;
m_dwOverridesCount = stack.m_dwOverridesCount;
m_dwAsserts = stack.m_dwAsserts;
LOG((LF_APPDOMAIN, LL_INFO100, "copy ctor: m_dwAsserts:%d stack.m_dwAsserts:%d\n",m_dwAsserts, stack.m_dwAsserts));
memcpy(m_pStack, stack.m_pStack, sizeof( AppDomainStackEntry) * ADSTACK_BLOCK_SIZE);
// If there is anything stored in the extra allocated space, copy that over
if (m_numEntries > ADSTACK_BLOCK_SIZE)
{
// #blocks to allocate = ceil(numDomains/blocksize) - 1 = ceil ((numdomains - blocksize)/blocksize) = numdomains/blocksize
DWORD numBlocks = m_numEntries/ADSTACK_BLOCK_SIZE;
m_ExtraStackSize = numBlocks*ADSTACK_BLOCK_SIZE;
m_pExtraStack = new AppDomainStackEntry[m_ExtraStackSize];
memcpy(m_pExtraStack, stack.m_pExtraStack, sizeof(AppDomainStackEntry)*(m_numEntries-ADSTACK_BLOCK_SIZE));
FillEntries((m_pExtraStack+m_numEntries-ADSTACK_BLOCK_SIZE), (m_ExtraStackSize -(m_numEntries-ADSTACK_BLOCK_SIZE)));
}
}
~AppDomainStack()
{
CONTRACTL
{
MODE_ANY;
GC_NOTRIGGER;
NOTHROW;
} CONTRACTL_END;
if (m_pExtraStack != NULL)
delete[] m_pExtraStack;
m_pExtraStack = NULL;
m_ExtraStackSize = 0;
}
bool operator!= (const AppDomainStack& stack) const
{
return !(*this == stack);
}
bool operator== (const AppDomainStack& stack) const
{
LEAF_CONTRACT;
if (this == &stack) // degenerate case: comparing with self
return true;
if (this->m_numEntries != stack.m_numEntries ||
this->m_dwAsserts != stack.m_dwAsserts ||
this->m_dwOverridesCount != stack.m_dwOverridesCount)
return false;
for (unsigned i =0; i < stack.m_numEntries; i++)
{
if (i < ADSTACK_BLOCK_SIZE)
{
if (this->m_pStack[i] != stack.m_pStack[i])
return false;
}
else
{
if (this->m_pExtraStack[i-ADSTACK_BLOCK_SIZE] != stack.m_pExtraStack[i-ADSTACK_BLOCK_SIZE])
return false;
}
}
return true;
}
inline AppDomainStack& operator =(const AppDomainStack& stack)
{
CONTRACTL {
THROWS;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
// Degenerate case (assigning x = x)
if (this == &stack)
return *this;
m_dwThreadWideSpecialFlags = stack.m_dwThreadWideSpecialFlags;
m_numEntries = stack.m_numEntries;
m_dwOverridesCount = stack.m_dwOverridesCount;
m_dwAsserts = stack.m_dwAsserts;
LOG((LF_APPDOMAIN, LL_INFO100, "= operator : m_dwAsserts:%d stack.m_dwAsserts:%d\n",m_dwAsserts, stack.m_dwAsserts));
memcpy(m_pStack, stack.m_pStack, sizeof( AppDomainStackEntry) * ADSTACK_BLOCK_SIZE);
// If there is anything stored in the extra allocated space, copy that over
if (m_numEntries > ADSTACK_BLOCK_SIZE)
{
// #blocks to allocate = ceil(numDomains/blocksize) - 1 = ceil ((numdomains - blocksize)/blocksize) = numdomains/blocksize
DWORD numBlocks = m_numEntries/ADSTACK_BLOCK_SIZE;
if (m_ExtraStackSize < numBlocks*ADSTACK_BLOCK_SIZE)
{
// free ptr if it exists
if (m_pExtraStack != NULL)
delete[] m_pExtraStack;
m_pExtraStack = NULL;
m_ExtraStackSize = numBlocks*ADSTACK_BLOCK_SIZE;
m_pExtraStack = new AppDomainStackEntry[m_ExtraStackSize];
}
memset(m_pExtraStack, 0xFF, sizeof(ADID) * numBlocks);
memcpy(m_pExtraStack, stack.m_pExtraStack, sizeof(AppDomainStackEntry)*(m_numEntries-ADSTACK_BLOCK_SIZE));
FillEntries((m_pExtraStack+m_numEntries-ADSTACK_BLOCK_SIZE), (m_ExtraStackSize -(m_numEntries-ADSTACK_BLOCK_SIZE)));
}
return *this;
}
inline void PushDomain(ADID pDomain);
inline ADID PopDomain();
inline void InitDomainIteration(DWORD *pIndex) const;
// Gets the next AD on the stack
inline ADID GetNextDomainOnStack(DWORD *pIndex, DWORD *pOverrides, DWORD *pAsserts) const;
inline AppDomainStackEntry* GetNextDomainEntryOnStack(DWORD *pIndex);
inline AppDomainStackEntry* GetCurrentDomainEntryOnStack(DWORD pIndex);
// Updates the asserts/overrides on the next AD on the stack
inline void UpdateDomainOnStack(DWORD pIndex, DWORD asserts, DWORD overrides);
inline DWORD GetNumDomains() const;
inline void ClearDomainStack();
inline DWORD GetThreadWideSpecialFlag() const;
inline DWORD IncrementOverridesCount();
inline DWORD DecrementOverridesCount();
inline DWORD GetOverridesCount();
inline DWORD GetInnerAppDomainOverridesCount();
inline DWORD IncrementAssertCount();
inline DWORD DecrementAssertCount();
inline DWORD GetAssertCount();
inline DWORD GetInnerAppDomainAssertCount();
bool IsDefaultSecurityInfo() const;
BOOL AllDomainsHomogeneousWithNoStackModifiers();
private:
inline void AddMoreDomains(void);
inline AppDomainStackEntry* ReadTopOfStack();
void UpdateStackFromEntries();
static void AppDomainStack::FillEntries(AppDomainStackEntry ptr[], DWORD size)
{
CONTRACTL
{
MODE_ANY;
GC_NOTRIGGER;
NOTHROW;
}CONTRACTL_END;
_ASSERTE(ptr != NULL);
DWORD i;
const AppDomainStackEntry tmp_entry = {ADID(INVALID_APPDOMAIN_ID), 0, 0};
for(i=0;i<size;i++)
ptr[i]=tmp_entry;
}
#ifdef _DEBUG
inline void LogADStackUpdate(void);
void CheckOverridesAssertCounts(); // Debug only code to check that assert count/overrides count are always in sync across adstack
#endif
DWORD m_numEntries;
AppDomainStackEntry m_pStack[ADSTACK_BLOCK_SIZE];
AppDomainStackEntry *m_pExtraStack;
DWORD m_ExtraStackSize;
DWORD m_dwOverridesCount; // across all entries
DWORD m_dwAsserts; // across all entries
DWORD m_dwThreadWideSpecialFlags; // this flag records the last evaluated thread wide security state
};
#endif