1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// File: HotHeap.cpp
6//
7
8//
9// Class code:MetaData::HotHeap represents a hot heap in MetaData hot stream.
10//
11// ======================================================================================
12
13#include "external.h"
14
15#include "hotheap.h"
16#include "hotdataformat.h"
17#include <utilcode.h>
18
19namespace MetaData
20{
21
22// --------------------------------------------------------------------------------------
23//
24// Initializes hot heap from its header and data.
25// Provides limited debug-only validation of the structure.
26//
27__checkReturn
28HRESULT
29HotHeap::Initialize(
30 struct HotHeapHeader *pHotHeapHeader,
31 DataBuffer hotHeapData)
32{
33 _ASSERTE(hotHeapData.GetDataPointerBehind() == reinterpret_cast<BYTE *>(pHotHeapHeader));
34
35 UINT32 nMaximumNegativeOffset = hotHeapData.GetSize();
36 if (pHotHeapHeader->m_nIndexTableStart_NegativeOffset > nMaximumNegativeOffset)
37 {
38 m_pHotHeapHeader = NULL;
39 Debug_ReportError("Invalid hot heap header format - invalid index table offset.");
40 return METADATA_E_INVALID_FORMAT;
41 }
42 if ((pHotHeapHeader->m_nIndexTableStart_NegativeOffset % 4) != 0)
43 {
44 m_pHotHeapHeader = NULL;
45 Debug_ReportError("Invalid hot heap header format - index table offset is not aligned.");
46 return METADATA_E_INVALID_FORMAT;
47 }
48 if (pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset > nMaximumNegativeOffset)
49 {
50 m_pHotHeapHeader = NULL;
51 Debug_ReportError("Invalid hot heap header format - invalid value offset table offset.");
52 return METADATA_E_INVALID_FORMAT;
53 }
54 if ((pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset % 4) != 0)
55 {
56 m_pHotHeapHeader = NULL;
57 Debug_ReportError("Invalid hot heap header format - value offset table offset is not aligned.");
58 return METADATA_E_INVALID_FORMAT;
59 }
60 // Index table has to be behind value offset table
61 if (pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset < pHotHeapHeader->m_nIndexTableStart_NegativeOffset)
62 {
63 m_pHotHeapHeader = NULL;
64 Debug_ReportError("Invalid hot heap header format - value offset table doesn't start before index table.");
65 return METADATA_E_INVALID_FORMAT;
66 }
67 if (pHotHeapHeader->m_nValueHeapStart_NegativeOffset > nMaximumNegativeOffset)
68 {
69 m_pHotHeapHeader = NULL;
70 Debug_ReportError("Invalid hot heap header format - invalid value heap offset.");
71 return METADATA_E_INVALID_FORMAT;
72 }
73 m_pHotHeapHeader = pHotHeapHeader;
74 return S_OK;
75} // HotHeap::Initialize
76
77#ifdef _DEBUG_METADATA
78// --------------------------------------------------------------------------------------
79//
80// Validates hot heap structure (extension of code:Initialize checks).
81//
82__checkReturn
83HRESULT
84HotHeap::Debug_Validate()
85{
86 // Additional verification, more strict checks than in code:Initialize
87 S_UINT32 nValueOffsetTableStart =
88 S_UINT32(2) *
89 S_UINT32(m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset);
90 if (nValueOffsetTableStart.IsOverflow() ||
91 (nValueOffsetTableStart.Value() != m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset))
92 {
93 Debug_ReportError("Invalid hot heap header format.");
94 return METADATA_E_INVALID_FORMAT;
95 }
96 if (m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset <= m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset)
97 {
98 Debug_ReportError("Invalid hot heap header format.");
99 return METADATA_E_INVALID_FORMAT;
100 }
101
102 // Already validated against underflow in code:Initialize
103 BYTE *pIndexTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset;
104 UINT32 *rgIndexTable = reinterpret_cast<UINT32 *>(pIndexTableStart);
105 // Already validated against underflow in code:Initialize
106 BYTE *pValueOffsetTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset;
107 UINT32 *rgValueOffsetTable = reinterpret_cast<UINT32 *>(pValueOffsetTableStart);
108 // Already validated against underflow in code:Initialize
109 BYTE *pValueHeapStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset;
110 DataBuffer valueHeap(
111 pValueHeapStart,
112 m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset);
113
114 // Already validated for % 4 == 0 in code:Initialize
115 UINT32 cIndexTableCount = m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset / 4;
116 UINT32 nPreviousValue = 0;
117 for (UINT32 nIndex = 0; nIndex < cIndexTableCount; nIndex++)
118 {
119 if (nPreviousValue >= rgIndexTable[nIndex])
120 {
121 Debug_ReportError("Invalid hot heap header format.");
122 return METADATA_E_INVALID_FORMAT;
123 }
124 UINT32 nValueOffset = rgValueOffsetTable[nIndex];
125 if (nValueOffset >= valueHeap.GetSize())
126 {
127 Debug_ReportError("Invalid hot heap header format.");
128 return METADATA_E_INVALID_FORMAT;
129 }
130 // TODO: Verify item (depends if it is string, blob, guid or user string)
131 }
132 return S_OK;
133} // HotHeap::Debug_Validate
134#endif //_DEBUG_METADATA
135
136// --------------------------------------------------------------------------------------
137//
138// Gets stored data at index.
139// Returns S_FALSE if data index is not stored in hot heap.
140//
141__checkReturn
142HRESULT
143HotHeap::GetData(
144 UINT32 nDataIndex,
145 __in DataBlob *pData)
146{
147 // Already validated against underflow in code:Initialize
148 BYTE *pIndexTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset;
149 // Already validated against underflow in code:Initialize
150 BYTE *pValueOffsetTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset;
151 // Already validated against underflow in code:Initialize
152 BYTE *pValueHeapStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset;
153
154 const UINT32 *pnFoundDataIndex = BinarySearch<UINT32>(
155 reinterpret_cast<UINT32 *>(pIndexTableStart),
156 m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset / sizeof(UINT32),
157 nDataIndex);
158
159 if (pnFoundDataIndex == NULL)
160 { // Index is not stored in hot data
161 return S_FALSE;
162 }
163 _ASSERTE(((UINT32 *)pIndexTableStart <= pnFoundDataIndex) &&
164 (pnFoundDataIndex + 1 <= (UINT32 *)m_pHotHeapHeader));
165
166 // Index of found data index in the index table (note: it is not offset, but really index)
167 UINT32 nIndexOfFoundDataIndex = (UINT32)(pnFoundDataIndex - (UINT32 *)pIndexTableStart);
168
169 // Value offset contains positive offset to the ValueHeap start
170 // Already validated against overflow in code:Initialize
171 UINT32 nValueOffset_PositiveOffset = reinterpret_cast<UINT32 *>(pValueOffsetTableStart)[nIndexOfFoundDataIndex];
172 if (nValueOffset_PositiveOffset >= m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset)
173 {
174 pData->Clear();
175 Debug_ReportError("Invalid hot data format - value offset reaches behind the hot heap data.");
176 return METADATA_E_INVALID_FORMAT;
177 }
178 pData->Init(
179 pValueHeapStart + nValueOffset_PositiveOffset,
180 m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset - nValueOffset_PositiveOffset);
181
182 return S_OK;
183} // HotHeap::GetData
184
185}; // namespace MetaData
186