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 | |
19 | namespace 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 |
28 | HRESULT |
29 | HotHeap::( |
30 | struct HotHeapHeader *, |
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 |
83 | HRESULT |
84 | HotHeap::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 |
142 | HRESULT |
143 | HotHeap::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 | |