summaryrefslogtreecommitdiff
path: root/src/md/hotdata/hotheap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/hotdata/hotheap.cpp')
-rw-r--r--src/md/hotdata/hotheap.cpp185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/md/hotdata/hotheap.cpp b/src/md/hotdata/hotheap.cpp
new file mode 100644
index 0000000000..ac53d23aff
--- /dev/null
+++ b/src/md/hotdata/hotheap.cpp
@@ -0,0 +1,185 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeap.cpp
+//
+
+//
+// Class code:MetaData::HotHeap represents a hot heap in MetaData hot stream.
+//
+// ======================================================================================
+
+#include "external.h"
+
+#include "hotheap.h"
+#include "hotdataformat.h"
+#include <utilcode.h>
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// Initializes hot heap from its header and data.
+// Provides limited debug-only validation of the structure.
+//
+__checkReturn
+HRESULT
+HotHeap::Initialize(
+ struct HotHeapHeader *pHotHeapHeader,
+ DataBuffer hotHeapData)
+{
+ _ASSERTE(hotHeapData.GetDataPointerBehind() == reinterpret_cast<BYTE *>(pHotHeapHeader));
+
+ UINT32 nMaximumNegativeOffset = hotHeapData.GetSize();
+ if (pHotHeapHeader->m_nIndexTableStart_NegativeOffset > nMaximumNegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - invalid index table offset.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if ((pHotHeapHeader->m_nIndexTableStart_NegativeOffset % 4) != 0)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - index table offset is not aligned.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if (pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset > nMaximumNegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - invalid value offset table offset.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if ((pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset % 4) != 0)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - value offset table offset is not aligned.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ // Index table has to be behind value offset table
+ if (pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset < pHotHeapHeader->m_nIndexTableStart_NegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - value offset table doesn't start before index table.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if (pHotHeapHeader->m_nValueHeapStart_NegativeOffset > nMaximumNegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - invalid value heap offset.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ m_pHotHeapHeader = pHotHeapHeader;
+ return S_OK;
+} // HotHeap::Initialize
+
+#ifdef _DEBUG_METADATA
+// --------------------------------------------------------------------------------------
+//
+// Validates hot heap structure (extension of code:Initialize checks).
+//
+__checkReturn
+HRESULT
+HotHeap::Debug_Validate()
+{
+ // Additional verification, more strict checks than in code:Initialize
+ S_UINT32 nValueOffsetTableStart =
+ S_UINT32(2) *
+ S_UINT32(m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset);
+ if (nValueOffsetTableStart.IsOverflow() ||
+ (nValueOffsetTableStart.Value() != m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset))
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if (m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset <= m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset)
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+
+ // Already validated against underflow in code:Initialize
+ BYTE *pIndexTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset;
+ UINT32 *rgIndexTable = reinterpret_cast<UINT32 *>(pIndexTableStart);
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueOffsetTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset;
+ UINT32 *rgValueOffsetTable = reinterpret_cast<UINT32 *>(pValueOffsetTableStart);
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueHeapStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset;
+ DataBuffer valueHeap(
+ pValueHeapStart,
+ m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset);
+
+ // Already validated for % 4 == 0 in code:Initialize
+ UINT32 cIndexTableCount = m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset / 4;
+ UINT32 nPreviousValue = 0;
+ for (UINT32 nIndex = 0; nIndex < cIndexTableCount; nIndex++)
+ {
+ if (nPreviousValue >= rgIndexTable[nIndex])
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ UINT32 nValueOffset = rgValueOffsetTable[nIndex];
+ if (nValueOffset >= valueHeap.GetSize())
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ // TODO: Verify item (depends if it is string, blob, guid or user string)
+ }
+ return S_OK;
+} // HotHeap::Debug_Validate
+#endif //_DEBUG_METADATA
+
+// --------------------------------------------------------------------------------------
+//
+// Gets stored data at index.
+// Returns S_FALSE if data index is not stored in hot heap.
+//
+__checkReturn
+HRESULT
+HotHeap::GetData(
+ UINT32 nDataIndex,
+ __in DataBlob *pData)
+{
+ // Already validated against underflow in code:Initialize
+ BYTE *pIndexTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset;
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueOffsetTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset;
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueHeapStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset;
+
+ const UINT32 *pnFoundDataIndex = BinarySearch<UINT32>(
+ reinterpret_cast<UINT32 *>(pIndexTableStart),
+ m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset / sizeof(UINT32),
+ nDataIndex);
+
+ if (pnFoundDataIndex == NULL)
+ { // Index is not stored in hot data
+ return S_FALSE;
+ }
+ _ASSERTE(((UINT32 *)pIndexTableStart <= pnFoundDataIndex) &&
+ (pnFoundDataIndex + 1 <= (UINT32 *)m_pHotHeapHeader));
+
+ // Index of found data index in the index table (note: it is not offset, but really index)
+ UINT32 nIndexOfFoundDataIndex = (UINT32)(pnFoundDataIndex - (UINT32 *)pIndexTableStart);
+
+ // Value offset contains positive offset to the ValueHeap start
+ // Already validated against overflow in code:Initialize
+ UINT32 nValueOffset_PositiveOffset = reinterpret_cast<UINT32 *>(pValueOffsetTableStart)[nIndexOfFoundDataIndex];
+ if (nValueOffset_PositiveOffset >= m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset)
+ {
+ pData->Clear();
+ Debug_ReportError("Invalid hot data format - value offset reaches behind the hot heap data.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ pData->Init(
+ pValueHeapStart + nValueOffset_PositiveOffset,
+ m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset - nValueOffset_PositiveOffset);
+
+ return S_OK;
+} // HotHeap::GetData
+
+}; // namespace MetaData