Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit e4c3163

Browse files
Add in-memory logging for virtual memory operations.
1 parent 37e7654 commit e4c3163

File tree

1 file changed

+141
-2
lines changed

1 file changed

+141
-2
lines changed

src/pal/src/map/virtual.cpp

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,77 @@ static LPVOID ReserveVirtualMemory(
7373
// of virtual memory that is located near the CoreCLR library.
7474
static ExecutableMemoryAllocator g_executableMemoryAllocator;
7575

76+
//
77+
//
78+
// Virtual Memory Logging
79+
//
80+
// We maintain a lightweight in-memory circular buffer recording virtual
81+
// memory operations so that we can better diagnose failures and crashes
82+
// caused by one of these operations mishandling memory in some way.
83+
//
84+
//
85+
namespace VirtualMemoryLogging
86+
{
87+
// Specifies the operation being logged
88+
enum class VirtualOperation
89+
{
90+
Allocate = 0x10,
91+
Reserve = 0x20,
92+
Commit = 0x30,
93+
Decommit = 0x40,
94+
Release = 0x50,
95+
};
96+
97+
// Indicates that the attempted operation has failed
98+
const DWORD FailedOperationMarker = 0x80000000;
99+
100+
// An entry in the in-memory log
101+
struct LogRecord
102+
{
103+
LONG RecordId;
104+
DWORD Operation;
105+
LPVOID CurrentThread;
106+
LPVOID RequestedAddress;
107+
LPVOID ReturnedAddress;
108+
SIZE_T Size;
109+
DWORD AllocationType;
110+
DWORD Protect;
111+
};
112+
113+
// Maximum number of records in the in-memory log
114+
const LONG MaxRecords = 128;
115+
116+
// Buffer used to store the logged data
117+
volatile LogRecord logRecords[MaxRecords];
118+
119+
// Current record number. Use (recordNumber % MaxRecords) to determine
120+
// the current position in the circular buffer.
121+
volatile LONG recordNumber = 0;
122+
123+
// Record an entry in the in-memory log
124+
void LogVaOperation(
125+
IN VirtualOperation operation,
126+
IN LPVOID requestedAddress,
127+
IN SIZE_T size,
128+
IN DWORD flAllocationType,
129+
IN DWORD flProtect,
130+
IN LPVOID returnedAddress,
131+
IN BOOL result)
132+
{
133+
LONG i = InterlockedIncrement(&recordNumber) - 1;
134+
LogRecord* curRec = (LogRecord*)&logRecords[i % MaxRecords];
135+
136+
curRec->RecordId = i;
137+
curRec->CurrentThread = (LPVOID)pthread_self();
138+
curRec->RequestedAddress = requestedAddress;
139+
curRec->ReturnedAddress = returnedAddress;
140+
curRec->Size = size;
141+
curRec->AllocationType = flAllocationType;
142+
curRec->Protect = flProtect;
143+
curRec->Operation = static_cast<DWORD>(operation) | (result ? 0 : FailedOperationMarker);
144+
}
145+
}
146+
76147
/*++
77148
Function:
78149
VIRTUALInitialize()
@@ -88,7 +159,7 @@ extern "C"
88159
BOOL
89160
VIRTUALInitialize(bool initializeExecutableMemoryAllocator)
90161
{
91-
TRACE( "Initializing the Virtual Critical Sections. \n" );
162+
TRACE("Initializing the Virtual Critical Sections. \n");
92163

93164
InternalInitializeCriticalSection(&virtual_critsec);
94165

@@ -604,6 +675,30 @@ static void VIRTUALDisplayList( void )
604675
}
605676
#endif
606677

678+
#ifdef DEBUG
679+
void VerifyRightEntry(PCMI pEntry)
680+
{
681+
volatile PCMI pRight = pEntry->pNext;
682+
SIZE_T endAddress;
683+
if (pRight != nullptr)
684+
{
685+
endAddress = ((SIZE_T)pEntry->startBoundary) + pEntry->memSize;
686+
_ASSERTE(endAddress <= (SIZE_T)pRight->startBoundary);
687+
}
688+
}
689+
690+
void VerifyLeftEntry(PCMI pEntry)
691+
{
692+
volatile PCMI pLeft = pEntry->pPrevious;
693+
SIZE_T endAddress;
694+
if (pLeft != NULL)
695+
{
696+
endAddress = ((SIZE_T)pLeft->startBoundary) + pLeft->memSize;
697+
_ASSERTE(endAddress <= (SIZE_T)pEntry->startBoundary);
698+
}
699+
}
700+
#endif // DEBUG
701+
607702
/****
608703
* VIRTUALStoreAllocationInfo()
609704
*
@@ -701,10 +796,15 @@ static BOOL VIRTUALStoreAllocationInfo(
701796
{
702797
pNewEntry->pNext->pPrevious = pNewEntry;
703798
}
704-
799+
705800
pVirtualMemory = pNewEntry ;
706801
}
707802

803+
#ifdef DEBUG
804+
VerifyRightEntry(pNewEntry);
805+
VerifyLeftEntry(pNewEntry);
806+
#endif // DEBUG
807+
708808
return TRUE;
709809
}
710810

@@ -772,6 +872,15 @@ static LPVOID VIRTUALReserveMemory(
772872
}
773873
}
774874

875+
LogVaOperation(
876+
VirtualMemoryLogging::VirtualOperation::Reserve,
877+
lpAddress,
878+
dwSize,
879+
flAllocationType,
880+
flProtect,
881+
pRetVal,
882+
pRetVal != NULL);
883+
775884
InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
776885
return pRetVal;
777886
}
@@ -1052,6 +1161,16 @@ VIRTUALCommitMemory(
10521161
}
10531162

10541163
done:
1164+
1165+
LogVaOperation(
1166+
VirtualMemoryLogging::VirtualOperation::Commit,
1167+
lpAddress,
1168+
dwSize,
1169+
flAllocationType,
1170+
flProtect,
1171+
pRetVal,
1172+
pRetVal != NULL);
1173+
10551174
return pRetVal;
10561175
}
10571176

@@ -1111,6 +1230,15 @@ VirtualAlloc(
11111230
WARN( "Ignoring the allocation flag MEM_TOP_DOWN.\n" );
11121231
}
11131232

1233+
LogVaOperation(
1234+
VirtualMemoryLogging::VirtualOperation::Allocate,
1235+
lpAddress,
1236+
dwSize,
1237+
flAllocationType,
1238+
flProtect,
1239+
NULL,
1240+
TRUE);
1241+
11141242
if ( flAllocationType & MEM_RESERVE )
11151243
{
11161244
InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
@@ -1319,6 +1447,17 @@ VirtualFree(
13191447
}
13201448

13211449
VirtualFreeExit:
1450+
1451+
LogVaOperation(
1452+
(dwFreeType & MEM_DECOMMIT) ? VirtualMemoryLogging::VirtualOperation::Decommit
1453+
: VirtualMemoryLogging::VirtualOperation::Release,
1454+
lpAddress,
1455+
dwSize,
1456+
dwFreeType,
1457+
0,
1458+
NULL,
1459+
bRetVal);
1460+
13221461
InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
13231462
LOGEXIT( "VirtualFree returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
13241463
PERF_EXIT(VirtualFree);

0 commit comments

Comments
 (0)