From e4c31637fd3f829e475627f71c1ebef2846bca00 Mon Sep 17 00:00:00 2001 From: Aditya Mandaleeka Date: Wed, 27 Jul 2016 17:37:45 -0700 Subject: [PATCH] Add in-memory logging for virtual memory operations. --- src/pal/src/map/virtual.cpp | 143 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 2 deletions(-) diff --git a/src/pal/src/map/virtual.cpp b/src/pal/src/map/virtual.cpp index f226e9c..e68ab78 100644 --- a/src/pal/src/map/virtual.cpp +++ b/src/pal/src/map/virtual.cpp @@ -73,6 +73,77 @@ static LPVOID ReserveVirtualMemory( // of virtual memory that is located near the CoreCLR library. static ExecutableMemoryAllocator g_executableMemoryAllocator; +// +// +// Virtual Memory Logging +// +// We maintain a lightweight in-memory circular buffer recording virtual +// memory operations so that we can better diagnose failures and crashes +// caused by one of these operations mishandling memory in some way. +// +// +namespace VirtualMemoryLogging +{ + // Specifies the operation being logged + enum class VirtualOperation + { + Allocate = 0x10, + Reserve = 0x20, + Commit = 0x30, + Decommit = 0x40, + Release = 0x50, + }; + + // Indicates that the attempted operation has failed + const DWORD FailedOperationMarker = 0x80000000; + + // An entry in the in-memory log + struct LogRecord + { + LONG RecordId; + DWORD Operation; + LPVOID CurrentThread; + LPVOID RequestedAddress; + LPVOID ReturnedAddress; + SIZE_T Size; + DWORD AllocationType; + DWORD Protect; + }; + + // Maximum number of records in the in-memory log + const LONG MaxRecords = 128; + + // Buffer used to store the logged data + volatile LogRecord logRecords[MaxRecords]; + + // Current record number. Use (recordNumber % MaxRecords) to determine + // the current position in the circular buffer. + volatile LONG recordNumber = 0; + + // Record an entry in the in-memory log + void LogVaOperation( + IN VirtualOperation operation, + IN LPVOID requestedAddress, + IN SIZE_T size, + IN DWORD flAllocationType, + IN DWORD flProtect, + IN LPVOID returnedAddress, + IN BOOL result) + { + LONG i = InterlockedIncrement(&recordNumber) - 1; + LogRecord* curRec = (LogRecord*)&logRecords[i % MaxRecords]; + + curRec->RecordId = i; + curRec->CurrentThread = (LPVOID)pthread_self(); + curRec->RequestedAddress = requestedAddress; + curRec->ReturnedAddress = returnedAddress; + curRec->Size = size; + curRec->AllocationType = flAllocationType; + curRec->Protect = flProtect; + curRec->Operation = static_cast(operation) | (result ? 0 : FailedOperationMarker); + } +} + /*++ Function: VIRTUALInitialize() @@ -88,7 +159,7 @@ extern "C" BOOL VIRTUALInitialize(bool initializeExecutableMemoryAllocator) { - TRACE( "Initializing the Virtual Critical Sections. \n" ); + TRACE("Initializing the Virtual Critical Sections. \n"); InternalInitializeCriticalSection(&virtual_critsec); @@ -604,6 +675,30 @@ static void VIRTUALDisplayList( void ) } #endif +#ifdef DEBUG +void VerifyRightEntry(PCMI pEntry) +{ + volatile PCMI pRight = pEntry->pNext; + SIZE_T endAddress; + if (pRight != nullptr) + { + endAddress = ((SIZE_T)pEntry->startBoundary) + pEntry->memSize; + _ASSERTE(endAddress <= (SIZE_T)pRight->startBoundary); + } +} + +void VerifyLeftEntry(PCMI pEntry) +{ + volatile PCMI pLeft = pEntry->pPrevious; + SIZE_T endAddress; + if (pLeft != NULL) + { + endAddress = ((SIZE_T)pLeft->startBoundary) + pLeft->memSize; + _ASSERTE(endAddress <= (SIZE_T)pEntry->startBoundary); + } +} +#endif // DEBUG + /**** * VIRTUALStoreAllocationInfo() * @@ -701,10 +796,15 @@ static BOOL VIRTUALStoreAllocationInfo( { pNewEntry->pNext->pPrevious = pNewEntry; } - + pVirtualMemory = pNewEntry ; } +#ifdef DEBUG + VerifyRightEntry(pNewEntry); + VerifyLeftEntry(pNewEntry); +#endif // DEBUG + return TRUE; } @@ -772,6 +872,15 @@ static LPVOID VIRTUALReserveMemory( } } + LogVaOperation( + VirtualMemoryLogging::VirtualOperation::Reserve, + lpAddress, + dwSize, + flAllocationType, + flProtect, + pRetVal, + pRetVal != NULL); + InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec); return pRetVal; } @@ -1052,6 +1161,16 @@ error: } done: + + LogVaOperation( + VirtualMemoryLogging::VirtualOperation::Commit, + lpAddress, + dwSize, + flAllocationType, + flProtect, + pRetVal, + pRetVal != NULL); + return pRetVal; } @@ -1111,6 +1230,15 @@ VirtualAlloc( WARN( "Ignoring the allocation flag MEM_TOP_DOWN.\n" ); } + LogVaOperation( + VirtualMemoryLogging::VirtualOperation::Allocate, + lpAddress, + dwSize, + flAllocationType, + flProtect, + NULL, + TRUE); + if ( flAllocationType & MEM_RESERVE ) { InternalEnterCriticalSection(pthrCurrent, &virtual_critsec); @@ -1319,6 +1447,17 @@ VirtualFree( } VirtualFreeExit: + + LogVaOperation( + (dwFreeType & MEM_DECOMMIT) ? VirtualMemoryLogging::VirtualOperation::Decommit + : VirtualMemoryLogging::VirtualOperation::Release, + lpAddress, + dwSize, + dwFreeType, + 0, + NULL, + bRetVal); + InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec); LOGEXIT( "VirtualFree returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" ); PERF_EXIT(VirtualFree); -- 2.7.4