@@ -73,6 +73,77 @@ static LPVOID ReserveVirtualMemory(
73
73
// of virtual memory that is located near the CoreCLR library.
74
74
static ExecutableMemoryAllocator g_executableMemoryAllocator;
75
75
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
+
76
147
/* ++
77
148
Function:
78
149
VIRTUALInitialize()
@@ -88,7 +159,7 @@ extern "C"
88
159
BOOL
89
160
VIRTUALInitialize (bool initializeExecutableMemoryAllocator)
90
161
{
91
- TRACE ( " Initializing the Virtual Critical Sections. \n " );
162
+ TRACE (" Initializing the Virtual Critical Sections. \n " );
92
163
93
164
InternalInitializeCriticalSection (&virtual_critsec);
94
165
@@ -604,6 +675,30 @@ static void VIRTUALDisplayList( void )
604
675
}
605
676
#endif
606
677
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
+
607
702
/* ***
608
703
* VIRTUALStoreAllocationInfo()
609
704
*
@@ -701,10 +796,15 @@ static BOOL VIRTUALStoreAllocationInfo(
701
796
{
702
797
pNewEntry->pNext ->pPrevious = pNewEntry;
703
798
}
704
-
799
+
705
800
pVirtualMemory = pNewEntry ;
706
801
}
707
802
803
+ #ifdef DEBUG
804
+ VerifyRightEntry (pNewEntry);
805
+ VerifyLeftEntry (pNewEntry);
806
+ #endif // DEBUG
807
+
708
808
return TRUE ;
709
809
}
710
810
@@ -772,6 +872,15 @@ static LPVOID VIRTUALReserveMemory(
772
872
}
773
873
}
774
874
875
+ LogVaOperation (
876
+ VirtualMemoryLogging::VirtualOperation::Reserve,
877
+ lpAddress,
878
+ dwSize,
879
+ flAllocationType,
880
+ flProtect,
881
+ pRetVal,
882
+ pRetVal != NULL );
883
+
775
884
InternalLeaveCriticalSection (pthrCurrent, &virtual_critsec);
776
885
return pRetVal;
777
886
}
@@ -1052,6 +1161,16 @@ VIRTUALCommitMemory(
1052
1161
}
1053
1162
1054
1163
done:
1164
+
1165
+ LogVaOperation (
1166
+ VirtualMemoryLogging::VirtualOperation::Commit,
1167
+ lpAddress,
1168
+ dwSize,
1169
+ flAllocationType,
1170
+ flProtect,
1171
+ pRetVal,
1172
+ pRetVal != NULL );
1173
+
1055
1174
return pRetVal;
1056
1175
}
1057
1176
@@ -1111,6 +1230,15 @@ VirtualAlloc(
1111
1230
WARN ( " Ignoring the allocation flag MEM_TOP_DOWN.\n " );
1112
1231
}
1113
1232
1233
+ LogVaOperation (
1234
+ VirtualMemoryLogging::VirtualOperation::Allocate,
1235
+ lpAddress,
1236
+ dwSize,
1237
+ flAllocationType,
1238
+ flProtect,
1239
+ NULL ,
1240
+ TRUE );
1241
+
1114
1242
if ( flAllocationType & MEM_RESERVE )
1115
1243
{
1116
1244
InternalEnterCriticalSection (pthrCurrent, &virtual_critsec);
@@ -1319,6 +1447,17 @@ VirtualFree(
1319
1447
}
1320
1448
1321
1449
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
+
1322
1461
InternalLeaveCriticalSection (pthrCurrent, &virtual_critsec);
1323
1462
LOGEXIT ( " VirtualFree returning %s.\n " , bRetVal == TRUE ? " TRUE" : " FALSE" );
1324
1463
PERF_EXIT (VirtualFree);
0 commit comments