Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix ARM write barrier icache flushing
Also allocate LoaderHeapFreeBlock from regular heap.
  • Loading branch information
janvorli committed Jul 10, 2021
commit 357c2831663c73b978eef2bd03e0005df2ddb70e
140 changes: 64 additions & 76 deletions src/coreclr/utilcode/loaderheap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,15 +695,21 @@ size_t AllocMem_TotalSize(size_t dwRequestedSize, UnlockedLoaderHeap *pHeap);
struct LoaderHeapFreeBlock
{
public:
LoaderHeapFreeBlock *m_pNext; // Pointer to next block on free list
size_t m_dwSize; // Total size of this block (including this header)
//! Try not to grow the size of this structure. It places a minimum size on LoaderHeap allocations.
LoaderHeapFreeBlock *m_pNext; // Pointer to next block on free list
size_t m_dwSize; // Total size of this block
void *m_pBlockAddress; // Virtual address of the block

static void InsertFreeBlock(LoaderHeapFreeBlock **ppHead, void *pMemRX, void *pMemRW, size_t dwTotalSize, UnlockedLoaderHeap *pHeap)
#ifndef DACCESS_COMPILE
static void InsertFreeBlock(LoaderHeapFreeBlock **ppHead, void *pMem, size_t dwTotalSize, UnlockedLoaderHeap *pHeap)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;

// The new "nothrow" below failure is handled in a non-fault way, so
// make sure that callers with FORBID_FAULT can call this method without
// firing the contract violation assert.
PERMANENT_CONTRACT_VIOLATION(FaultViolation, ReasonContractInfrastructure);

LOADER_HEAP_BEGIN_TRAP_FAULT

// It's illegal to insert a free block that's smaller than the minimum sized allocation -
Expand All @@ -722,20 +728,30 @@ struct LoaderHeapFreeBlock
}
#endif

INDEBUG(memset(pMemRW, 0xcc, dwTotalSize);)
LoaderHeapFreeBlock *pNewBlockRX = (LoaderHeapFreeBlock*)pMemRX;
LoaderHeapFreeBlock *pNewBlockRW = (LoaderHeapFreeBlock*)pMemRW;
pNewBlockRW->m_pNext = *ppHead;
pNewBlockRW->m_dwSize = dwTotalSize;
*ppHead = pNewBlockRX;
void* pMemRW = pMem;
ExecutableWriterHolder<void> memWriterHolder;
if (pHeap->IsExecutable())
{
memWriterHolder = ExecutableWriterHolder<void>(pMem, dwTotalSize);
pMemRW = memWriterHolder.GetRW();
}

MergeBlock(pNewBlockRX, pNewBlockRW, pHeap);
INDEBUG(memset(pMemRW, 0xcc, dwTotalSize);)
LoaderHeapFreeBlock *pNewBlock = new (nothrow) LoaderHeapFreeBlock;
// If we fail allocating the LoaderHeapFreeBlock, ignore the failure and don't insert the free block at all.
if (pNewBlock != NULL)
{
pNewBlock->m_pNext = *ppHead;
pNewBlock->m_dwSize = dwTotalSize;
pNewBlock->m_pBlockAddress = pMem;
*ppHead = pNewBlock;
MergeBlock(pNewBlock, pHeap);
}

LOADER_HEAP_END_TRAP_FAULT
}

#ifndef DACCESS_COMPILE
static void *AllocFromFreeList(LoaderHeapFreeBlock **ppHead, size_t dwSize, BOOL fRemoveFromFreeList, UnlockedLoaderHeap *pHeap)
static void *AllocFromFreeList(LoaderHeapFreeBlock **ppHead, size_t dwSize, UnlockedLoaderHeap *pHeap)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_NOTRIGGER;
Expand All @@ -752,46 +768,19 @@ struct LoaderHeapFreeBlock
size_t dwCurSize = pCur->m_dwSize;
if (dwCurSize == dwSize)
{
pResult = pCur;
pResult = pCur->m_pBlockAddress;
// Exact match. Hooray!
if (fRemoveFromFreeList)
{
ExecutableWriterHolder<LoaderHeapFreeBlock *> walkWriterHolder;
LoaderHeapFreeBlock **ppWalkRW = ppWalk;
if (pHeap->IsExecutable() && (ppWalk != ppHead))
{
walkWriterHolder = ExecutableWriterHolder<LoaderHeapFreeBlock *>(ppWalk, sizeof(LoaderHeapFreeBlock **));
ppWalkRW = walkWriterHolder.GetRW();
}
*ppWalkRW = pCur->m_pNext;
}
*ppWalk = pCur->m_pNext;
delete pCur;
break;
}
else if (dwCurSize > dwSize && (dwCurSize - dwSize) >= AllocMem_TotalSize(1, pHeap))
{
// Partial match. Ok...
pResult = pCur;
if (fRemoveFromFreeList)
{
ExecutableWriterHolder<LoaderHeapFreeBlock *> walkWriterHolder;
LoaderHeapFreeBlock **ppWalkRW = ppWalk;
if (pHeap->IsExecutable() && (ppWalk != ppHead))
{
walkWriterHolder = ExecutableWriterHolder<LoaderHeapFreeBlock *>(ppWalk, sizeof(LoaderHeapFreeBlock **));
ppWalkRW = walkWriterHolder.GetRW();
}
*ppWalkRW = pCur->m_pNext;

void* pMem = (BYTE*)pCur + dwSize;
void* pMemRW = pMem;
ExecutableWriterHolder<void> memWriterHolder;
if (pHeap->IsExecutable())
{
memWriterHolder = ExecutableWriterHolder<void>(pMem, dwSize);
pMemRW = memWriterHolder.GetRW();
}
InsertFreeBlock(ppWalkRW, pMem, pMemRW, dwCurSize - dwSize, pHeap );
}
pResult = pCur->m_pBlockAddress;
*ppWalk = pCur->m_pNext;
InsertFreeBlock(ppWalk, ((BYTE*)pCur->m_pBlockAddress) + dwSize, dwCurSize - dwSize, pHeap );
delete pCur;
break;
}

Expand All @@ -801,7 +790,7 @@ struct LoaderHeapFreeBlock
ppWalk = &( pCur->m_pNext );
}

if (pResult && fRemoveFromFreeList)
if (pResult)
{
void *pResultRW = pResult;
ExecutableWriterHolder<void> resultWriterHolder;
Expand All @@ -815,36 +804,40 @@ struct LoaderHeapFreeBlock
}
LOADER_HEAP_END_TRAP_FAULT
return pResult;



}
#endif // DACCESS_COMPILE

private:
// Try to merge pFreeBlock with its immediate successor. Return TRUE if a merge happened. FALSE if no merge happened.
static BOOL MergeBlock(LoaderHeapFreeBlock *pFreeBlockRX, LoaderHeapFreeBlock *pFreeBlockRW, UnlockedLoaderHeap *pHeap)
static BOOL MergeBlock(LoaderHeapFreeBlock *pFreeBlock, UnlockedLoaderHeap *pHeap)
{
STATIC_CONTRACT_NOTHROW;

BOOL result = FALSE;

LOADER_HEAP_BEGIN_TRAP_FAULT

LoaderHeapFreeBlock *pNextBlock = pFreeBlockRX->m_pNext;
size_t dwSize = pFreeBlockRX->m_dwSize;
LoaderHeapFreeBlock *pNextBlock = pFreeBlock->m_pNext;
size_t dwSize = pFreeBlock->m_dwSize;

if (pNextBlock == NULL || ((BYTE*)pNextBlock) != (((BYTE*)pFreeBlockRX) + dwSize))
if (pNextBlock == NULL || ((BYTE*)pNextBlock->m_pBlockAddress) != (((BYTE*)pFreeBlock->m_pBlockAddress) + dwSize))
{
result = FALSE;
}
else
{
size_t dwCombinedSize = dwSize + pNextBlock->m_dwSize;
LoaderHeapFreeBlock *pNextNextBlock = pNextBlock->m_pNext;
INDEBUG(memset(pFreeBlockRW, 0xcc, dwCombinedSize);)
pFreeBlockRW->m_pNext = pNextNextBlock;
pFreeBlockRW->m_dwSize = dwCombinedSize;
void *pMemRW = pFreeBlock->m_pBlockAddress;
ExecutableWriterHolder<void> memWriterHolder;
if (pHeap->IsExecutable())
{
memWriterHolder = ExecutableWriterHolder<void>(pFreeBlock->m_pBlockAddress, dwCombinedSize);
pMemRW = memWriterHolder.GetRW();
}
INDEBUG(memset(pMemRW, 0xcc, dwCombinedSize);)
pFreeBlock->m_pNext = pNextNextBlock;
pFreeBlock->m_dwSize = dwCombinedSize;
delete pNextBlock;

result = TRUE;
}
Expand All @@ -853,7 +846,7 @@ struct LoaderHeapFreeBlock
return result;

}

#endif // DACCESS_COMPILE
};


Expand All @@ -871,8 +864,7 @@ struct LoaderHeapFreeBlock
// - z bytes of pad (DEBUG-ONLY) (where "z" is just enough to pointer-align the following byte)
// - a bytes of tag (DEBUG-ONLY) (where "a" is sizeof(LoaderHeapValidationTag)
//
// - b bytes of pad (if total size after all this < sizeof(LoaderHeapFreeBlock), pad enough to make it the size of LoaderHeapFreeBlock)
// - c bytes of pad (where "c" is just enough to pointer-align the following byte)
// - b bytes of pad (where "b" is just enough to pointer-align the following byte)
//
// ==> Following address is always pointer-aligned
//=====================================================================================
Expand All @@ -893,10 +885,6 @@ inline size_t AllocMem_TotalSize(size_t dwRequestedSize, UnlockedLoaderHeap *pHe
#ifdef _DEBUG
dwSize += sizeof(LoaderHeapValidationTag);
#endif
if (dwSize < sizeof(LoaderHeapFreeBlock))
{
dwSize = sizeof(LoaderHeapFreeBlock);
}
}
dwSize = ((dwSize + ALLOC_ALIGN_CONSTANT) & (~ALLOC_ALIGN_CONSTANT));

Expand Down Expand Up @@ -1345,7 +1333,7 @@ void *UnlockedLoaderHeap::UnlockedAllocMem_NoThrow(size_t dwSize

{
// Any memory available on the free list?
void *pData = LoaderHeapFreeBlock::AllocFromFreeList(&m_pFirstFreeBlock, dwSize, TRUE /*fRemoveFromFreeList*/, this);
void *pData = LoaderHeapFreeBlock::AllocFromFreeList(&m_pFirstFreeBlock, dwSize, this);
if (!pData)
{
// Enough bytes available in committed region?
Expand Down Expand Up @@ -1545,24 +1533,24 @@ void UnlockedLoaderHeap::UnlockedBackoutMem(void *pMem,
}
#endif

void *pMemRW = pMem;
ExecutableWriterHolder<void> memWriterHolder;
if (m_Options & LHF_EXECUTABLE)
{
memWriterHolder = ExecutableWriterHolder<void>(pMem, dwSize);
pMemRW = memWriterHolder.GetRW();
}

if (m_pAllocPtr == ( ((BYTE*)pMem) + dwSize ))
{
void *pMemRW = pMem;
ExecutableWriterHolder<void> memWriterHolder;
if (m_Options & LHF_EXECUTABLE)
{
memWriterHolder = ExecutableWriterHolder<void>(pMem, dwSize);
pMemRW = memWriterHolder.GetRW();
}

// Cool. This was the last block allocated. We can just undo the allocation instead
// of going to the freelist.
memset(pMemRW, 0x00, dwSize); // Fill freed region with 0
m_pAllocPtr = (BYTE*)pMem;
}
else
{
LoaderHeapFreeBlock::InsertFreeBlock(&m_pFirstFreeBlock, pMem, pMemRW, dwSize, this);
LoaderHeapFreeBlock::InsertFreeBlock(&m_pFirstFreeBlock, pMem, dwSize, this);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/arm/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ void ComputeWriteBarrierRange(BYTE ** ppbStart, DWORD * pcbLength)
{
DWORD size = (PBYTE)JIT_PatchedWriteBarrierLast - (PBYTE)JIT_PatchedWriteBarrierStart;
*ppbStart = (PBYTE)JIT_PatchedWriteBarrierStart;
if (IsWriteBarrierCopyEnabled())
{
*ppbStart = GetWriteBarrierCodeLocation(*ppbStart);
}
*pcbLength = size;
}

Expand Down