Skip to content

Commit ab452c8

Browse files
committed
Fix corruption in virtual methods cache table
1 parent 542bc41 commit ab452c8

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

src/CLR/Core/Cache.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,81 @@ void CLR_RT_EventCache::VirtualMethodTable::Initialize()
196196
m_entriesMRU = (Link *)&g_scratchVirtualMethodTableLinkMRU[0];
197197
m_payloads = (Payload *)&g_scratchVirtualMethodPayload[0];
198198

199+
#ifdef DEBUG
200+
201+
// DIAGNOSTIC: Verify structure sizes and alignment
202+
CLR_Debug::Printf("\r\n========== VirtualMethodTable::Initialize DIAGNOSTICS ==========\r\n");
203+
CLR_Debug::Printf("sizeof(Link) = %u, alignof(Link) = %u\r\n", sizeof(Link), alignof(Link));
204+
CLR_Debug::Printf("sizeof(Payload) = %u, alignof(Payload) = %u\r\n", sizeof(Payload), alignof(Payload));
205+
CLR_Debug::Printf("sizeof(Payload::Key) = %u\r\n", sizeof(Payload::Key));
206+
CLR_Debug::Printf("LinkArraySize() = %u (expected: 641)\r\n", LinkArraySize());
207+
CLR_Debug::Printf("LinkMRUArraySize() = %u (expected: 513)\r\n", LinkMRUArraySize());
208+
CLR_Debug::Printf("PayloadArraySize() = %u (expected: 512)\r\n", PayloadArraySize());
209+
210+
// Verify array base addresses don't overlap
211+
uintptr_t entries_start = (uintptr_t)m_entries;
212+
uintptr_t entries_end = entries_start + (LinkArraySize() * sizeof(Link));
213+
uintptr_t entriesMRU_start = (uintptr_t)m_entriesMRU;
214+
uintptr_t entriesMRU_end = entriesMRU_start + (LinkMRUArraySize() * sizeof(Link));
215+
uintptr_t payloads_start = (uintptr_t)m_payloads;
216+
uintptr_t payloads_end = payloads_start + (PayloadArraySize() * sizeof(Payload));
217+
218+
#ifdef _WIN64
219+
220+
CLR_Debug::Printf(
221+
"m_entries: 0x%" PRIx64 " - 0x% " PRIx64 " (%u bytes)\r\n",
222+
entries_start,
223+
entries_end,
224+
(unsigned int)(entries_end - entries_start));
225+
CLR_Debug::Printf(
226+
"m_entriesMRU: 0x%" PRIx64 " - 0x% " PRIx64 " (%u bytes)\r\n",
227+
entriesMRU_start,
228+
entriesMRU_end,
229+
(unsigned int)(entriesMRU_end - entriesMRU_start));
230+
CLR_Debug::Printf(
231+
"m_payloads: 0x% " PRIx64 " - 0x% " PRIx64 " (%u bytes)\r\n",
232+
payloads_start,
233+
payloads_end,
234+
(unsigned int)(payloads_end - payloads_start));
235+
236+
#else
237+
238+
CLR_Debug::Printf(
239+
"m_entries: 0x%08X - 0x%08X (%u bytes)\r\n",
240+
entries_start,
241+
entries_end,
242+
(unsigned int)(entries_end - entries_start));
243+
CLR_Debug::Printf(
244+
"m_entriesMRU: 0x%08X - 0x%08X (%u bytes)\r\n",
245+
entriesMRU_start,
246+
entriesMRU_end,
247+
(unsigned int)(entriesMRU_end - entriesMRU_start));
248+
CLR_Debug::Printf(
249+
"m_payloads: 0x%08X - 0x%08X (%u bytes)\r\n",
250+
payloads_start,
251+
payloads_end,
252+
(unsigned int)(payloads_end - payloads_start));
253+
254+
#endif
255+
256+
// Check for overlaps
257+
if (entries_end > entriesMRU_start && entries_start < entriesMRU_end)
258+
{
259+
CLR_Debug::Printf("*** WARNING: m_entries and m_entriesMRU OVERLAP! ***\r\n");
260+
}
261+
if (entries_end > payloads_start && entries_start < payloads_end)
262+
{
263+
CLR_Debug::Printf("*** WARNING: m_entries and m_payloads OVERLAP! ***\r\n");
264+
}
265+
if (entriesMRU_end > payloads_start && entriesMRU_start < payloads_end)
266+
{
267+
CLR_Debug::Printf("*** WARNING: m_entriesMRU and m_payloads OVERLAP! ***\r\n");
268+
}
269+
270+
CLR_Debug::Printf("================================================================\r\n\r\n");
271+
272+
#endif
273+
199274
//
200275
// Link all the entries to themselves => no elements in the lists.
201276
//
@@ -211,6 +286,7 @@ void CLR_RT_EventCache::VirtualMethodTable::Initialize()
211286
// Link all the entries to the following one => all the elements are in the MRU list.
212287
//
213288
_ASSERTE(LinkMRUArraySize() < 0xFFFF);
289+
214290
for (index = 0; index < LinkMRUArraySize(); index++)
215291
{
216292
Link &lnk = m_entriesMRU[index];
@@ -301,14 +377,36 @@ bool CLR_RT_EventCache::VirtualMethodTable::FindVirtualMethod(
301377

302378
for (index = m_entries[indexHead].m_next;; index = m_entries[index].m_next)
303379
{
380+
#if defined(DEBUG) && defined(_WIN64)
381+
CLR_Debug::Printf(" Loop: index=%u, indexHead=%u\r\n", index, indexHead);
382+
#endif
383+
384+
// validate index before using it to prevent crashes from corrupted data
385+
if (index >= LinkArraySize())
386+
{
387+
// !! corrupted index detected !!
388+
// // repair the hash chain and treat as cache miss
389+
m_entries[indexHead].m_next = indexHead;
390+
m_entries[indexHead].m_prev = indexHead;
391+
392+
index = indexHead;
393+
}
394+
304395
if (index != indexHead)
305396
{
397+
_ASSERTE(index < PayloadArraySize());
398+
306399
Payload &res = m_payloads[index];
307400

308401
if (res.m_key.m_mdVirtual.data != mdVirtualData)
402+
{
309403
continue;
404+
}
405+
310406
if (res.m_key.m_cls.data != clsData)
407+
{
311408
continue;
409+
}
312410

313411
md = res.m_md;
314412

@@ -317,10 +415,20 @@ bool CLR_RT_EventCache::VirtualMethodTable::FindVirtualMethod(
317415
else
318416
{
319417
if (g_CLR_RT_TypeSystem.FindVirtualMethodDef(cls, mdVirtual, md) == false)
418+
{
320419
return false;
420+
}
321421

322422
index = GetNewEntry();
323423

424+
#if defined(DEBUG) && defined(_WIN64)
425+
CLR_Debug::Printf(" GetNewEntry returned: %u\r\n", index);
426+
#endif
427+
428+
// initialize the entry's links before use to prevent corruption
429+
m_entries[index].m_next = index;
430+
m_entries[index].m_prev = index;
431+
324432
Payload &res = m_payloads[index];
325433

326434
res.m_md = md;

0 commit comments

Comments
 (0)