size_t * m_pPrivatePerfCounter_LoaderBytes;
- DWORD m_flProtect;
+ DWORD m_Options;
LoaderHeapFreeBlock *m_pFirstFreeBlock;
SIZE_T dwReservedRegionSize,
size_t *pPrivatePerfCounter_LoaderBytes = NULL,
RangeList *pRangeList = NULL,
- BOOL fMakeExecutable = FALSE);
+ BOOL fMakeExecutable = FALSE,
+ BOOL fZeroInit = TRUE);
~UnlockedLoaderHeap();
#endif
return m_dwTotalAlloc;
}
- BOOL IsExecutable()
- {
- return (PAGE_EXECUTE_READWRITE == m_flProtect);
- }
+ BOOL IsExecutable();
+ BOOL IsZeroInit();
public:
DWORD dwCommitBlockSize,
size_t *pPrivatePerfCounter_LoaderBytes = NULL,
RangeList *pRangeList = NULL,
- BOOL fMakeExecutable = FALSE
+ BOOL fMakeExecutable = FALSE,
+ BOOL fZeroInit = TRUE
)
: UnlockedLoaderHeap(dwReserveBlockSize,
dwCommitBlockSize,
NULL, 0,
pPrivatePerfCounter_LoaderBytes,
pRangeList,
- fMakeExecutable)
+ fMakeExecutable,
+ fZeroInit)
{
WRAPPER_NO_CONTRACT;
m_CriticalSection = NULL;
SIZE_T dwReservedRegionSize,
size_t *pPrivatePerfCounter_LoaderBytes = NULL,
RangeList *pRangeList = NULL,
- BOOL fMakeExecutable = FALSE
+ BOOL fMakeExecutable = FALSE,
+ BOOL fZeroInit = TRUE
)
: UnlockedLoaderHeap(dwReserveBlockSize,
dwCommitBlockSize,
dwReservedRegionSize,
pPrivatePerfCounter_LoaderBytes,
pRangeList,
- fMakeExecutable)
+ fMakeExecutable,
+ fZeroInit)
{
WRAPPER_NO_CONTRACT;
m_CriticalSection = NULL;
#define DONOT_DEFINE_ETW_CALLBACK
#include "eventtracebase.h"
+#define LHF_EXECUTABLE 0x1
+#define LHF_ZEROINIT 0x2
+
#ifndef DACCESS_COMPILE
INDEBUG(DWORD UnlockedLoaderHeap::s_dwNumInstancesOfLoaderHeaps = 0;)
SIZE_T dwReservedRegionSize,
size_t *pPrivatePerfCounter_LoaderBytes,
RangeList *pRangeList,
- BOOL fMakeExecutable)
+ BOOL fMakeExecutable,
+ BOOL fZeroInit)
{
CONTRACTL
{
m_pPrivatePerfCounter_LoaderBytes = pPrivatePerfCounter_LoaderBytes;
+ m_Options = 0;
if (fMakeExecutable)
- m_flProtect = PAGE_EXECUTE_READWRITE;
- else
- m_flProtect = PAGE_READWRITE;
+ m_Options |= LHF_EXECUTABLE;
+ if (fZeroInit)
+ m_Options |= LHF_ZEROINIT;
m_pFirstFreeBlock = NULL;
}
// Commit first set of pages, since it will contain the LoaderHeapBlock
- void *pTemp = ClrVirtualAlloc(pData, dwSizeToCommit, MEM_COMMIT, m_flProtect);
+ void *pTemp = ClrVirtualAlloc(pData, dwSizeToCommit, MEM_COMMIT, (m_Options & LHF_EXECUTABLE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
if (pTemp == NULL)
{
//_ASSERTE(!"Unable to ClrVirtualAlloc commit in a loaderheap");
dwSizeToCommit = ALIGN_UP(dwSizeToCommit, GetOsPageSize());
// Yes, so commit the desired number of reserved pages
- void *pData = ClrVirtualAlloc(m_pPtrToEndOfCommittedRegion, dwSizeToCommit, MEM_COMMIT, m_flProtect);
+ void *pData = ClrVirtualAlloc(m_pPtrToEndOfCommittedRegion, dwSizeToCommit, MEM_COMMIT, (m_Options & LHF_EXECUTABLE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
if (pData == NULL)
return FALSE;
// Don't fill the memory we allocated - it is assumed to be zeroed - fill the memory after it
memset(pAllocatedBytes + dwRequestedSize, 0xEE, LOADER_HEAP_DEBUG_BOUNDARY);
#endif
- if (dwRequestedSize > 0)
+ if ((dwRequestedSize > 0) && (m_Options & LHF_ZEROINIT))
{
_ASSERTE_MSG(pAllocatedBytes[0] == 0 && memcmp(pAllocatedBytes, pAllocatedBytes + 1, dwRequestedSize - 1) == 0,
"LoaderHeap must return zero-initialized memory");
{
// Cool. This was the last block allocated. We can just undo the allocation instead
// of going to the freelist.
- memset(pMem, 0, dwSize); // Must zero init this memory as AllocMem expect it
+ if (m_Options & LHF_ZEROINIT)
+ memset(pMem, 0x00, dwSize); // Fill freed region with 0
m_pAllocPtr = (BYTE*)pMem;
}
else
((BYTE*&)pResult) += extra;
+
#ifdef _DEBUG
BYTE *pAllocatedBytes = (BYTE *)pResult;
#if LOADER_HEAP_DEBUG_BOUNDARY > 0
memset(pAllocatedBytes + dwRequestedSize, 0xee, LOADER_HEAP_DEBUG_BOUNDARY);
#endif
- if (dwRequestedSize != 0)
+ if ((dwRequestedSize != 0) && (m_Options & LHF_ZEROINIT))
{
_ASSERTE_MSG(pAllocatedBytes[0] == 0 && memcmp(pAllocatedBytes, pAllocatedBytes + 1, dwRequestedSize - 1) == 0,
"LoaderHeap must return zero-initialized memory");
#endif // #ifndef DACCESS_COMPILE
+BOOL UnlockedLoaderHeap::IsExecutable()
+{
+ return (m_Options & LHF_EXECUTABLE);
+}
+
+BOOL UnlockedLoaderHeap::IsZeroInit()
+{
+ return (m_Options & LHF_ZEROINIT);
+}
+
#ifdef DACCESS_COMPILE
void UnlockedLoaderHeap::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
_ASSERTE(DbgIsExecutable(&m_movR10[0], &m_jmpRAX[3]-&m_movR10[0]));
}
+void UMEntryThunkCode::Poison()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_movR10[0] = X86_INSTR_INT3;
+}
+
UMEntryThunk* UMEntryThunk::Decode(LPVOID pCallback)
{
LIMITED_METHOD_CONTRACT;
BYTE m_padding2[5];
void Encode(BYTE* pTargetCode, void* pvSecretParam);
+ void Poison();
LPCBYTE GetEntryPoint() const
{
TADDR m_pvSecretParam;
void Encode(BYTE* pTargetCode, void* pvSecretParam);
+ void Poison();
LPCBYTE GetEntryPoint() const
{
FlushInstructionCache(GetCurrentProcess(),&m_code,sizeof(m_code));
}
+void UMEntryThunkCode::Poison()
+{
+ // Insert 'bkpt 0x00be' at the entry point
+ m_code[0] = 0xbebe;
+}
+
///////////////////////////// UNIMPLEMENTED //////////////////////////////////
#ifndef DACCESS_COMPILE
TADDR m_pvSecretParam;
void Encode(BYTE* pTargetCode, void* pvSecretParam);
+ void Poison();
LPCBYTE GetEntryPoint() const
{
FlushInstructionCache(GetCurrentProcess(),&m_code,sizeof(m_code));
}
+void UMEntryThunkCode::Poison()
+{
+
+}
#ifdef PROFILING_SUPPORTED
#include "proftoeeinterfaceimpl.h"
UMEntryThunk * p;
-#ifdef FEATURE_WINDOWSPHONE
// On the phone, use loader heap to save memory commit of regular executable heap
p = (UMEntryThunk *)(void *)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(sizeof(UMEntryThunk)));
-#else
- p = new (executable) UMEntryThunk;
- memset (p, 0, sizeof(*p));
-#endif
RETURN p;
}
{
WRAPPER_NO_CONTRACT;
-#ifdef FEATURE_WINDOWSPHONE
+ _ASSERTE(!SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->IsZeroInit());
+ m_code.Poison();
+
SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->BackoutMem(this, sizeof(UMEntryThunk));
-#else
- DeleteExecutable(this);
-#endif
}
VOID UMEntryThunk::FreeUMEntryThunk(UMEntryThunk* p)
{
DestroyLongWeakHandle(GetObjectHandle());
}
-
-#ifdef _DEBUG
- FillMemory(this, sizeof(*this), 0xcc);
-#endif
}
void Terminate();
const BYTE * m_execstub; // pointer to destination code // make sure the backpatched portion is dword aligned.
void Encode(BYTE* pTargetCode, void* pvSecretParam);
+ void Poison();
LPCBYTE GetEntryPoint() const
{
FlushInstructionCache(GetCurrentProcess(),GetEntryPoint(),sizeof(UMEntryThunkCode));
}
+void UMEntryThunkCode::Poison()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ m_movEAX = X86_INSTR_INT3;
+}
+
UMEntryThunk* UMEntryThunk::Decode(LPVOID pCallback)
{
LIMITED_METHOD_CONTRACT;
dwExecutableHeapReserveSize,
LOADERHEAP_PROFILE_COUNTER,
NULL,
- TRUE /* Make heap executable */);
+ TRUE /* Make heap executable */,
+ FALSE /* Disable zero-initialization (needed by UMEntryThunkCode::Poison) */
+ );
initReservedMem += dwExecutableHeapReserveSize;
}