From 8f4acea87462a212f1983b5d35452a12623c99e2 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sun, 1 Sep 2024 14:40:36 +0300 Subject: [PATCH] [SDK] Implement RTL debug bitmap This is a single header that wraps around the RTL bitmap API. It keeps track of the number of set bits and a hash of the bitmap. The integrity of the bitmap is checked on each call to any of the RTL bitmap APIs. This only works, if the bitmap is consistently modified using only RTL bitmap APIs and not manually messing with the bitmap buffer. --- sdk/include/reactos/dbgbitmap.h | 349 ++++++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 sdk/include/reactos/dbgbitmap.h diff --git a/sdk/include/reactos/dbgbitmap.h b/sdk/include/reactos/dbgbitmap.h new file mode 100644 index 00000000000..1e13de22a4f --- /dev/null +++ b/sdk/include/reactos/dbgbitmap.h @@ -0,0 +1,349 @@ +/* + * PROJECT: ReactOS SDK + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Helper functions to debug RTL_BITMAP + * COPYRIGHT: Copyright 2024 Timo Kreuzer + */ + +#pragma once + +#include + +typedef struct _RTL_BITMAP_DBG +{ + union + { + struct + { + ULONG SizeOfBitMap; + PULONG Buffer; + }; + RTL_BITMAP BitMap; + }; + ULONG NumberOfSetBits; + ULONG BitmapHash; +} RTL_BITMAP_DBG, *PRTL_BITMAP_DBG; + +static inline +ULONG fnv1a_hash(ULONG *data, size_t length) +{ + ULONG hash = 2166136261u; // FNV offset basis (a large prime number) + for (size_t i = 0; i < length; ++i) + { + hash ^= data[i]; + hash *= 16777619u; // FNV prime + } + return hash; +} + +static inline +ULONG +RtlComputeBitmapHashDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader) +{ + ULONG SizeInBytes = ALIGN_UP_BY(BitMapHeader->BitMap.SizeOfBitMap, 32) / 32; + return fnv1a_hash(BitMapHeader->BitMap.Buffer, SizeInBytes / sizeof(ULONG)); +} + +static inline +VOID +RtlValidateBitmapDbg( + _Inout_ PRTL_BITMAP_DBG BitMapHeader) +{ + ULONG NumberOfSetBits = RtlNumberOfSetBits(&BitMapHeader->BitMap); + ASSERT(BitMapHeader->NumberOfSetBits == NumberOfSetBits); + ULONG BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); + ASSERT(BitMapHeader->BitmapHash == BitmapHash); +} + +_At_(BitMapHeader->SizeOfBitMap, _Post_equal_to_(SizeOfBitMap)) +_At_(BitMapHeader->Buffer, _Post_equal_to_(BitMapBuffer)) +static inline +VOID +RtlInitializeBitMapDbg( + _Out_ PRTL_BITMAP_DBG BitMapHeader, + _In_opt_ __drv_aliasesMem PULONG BitMapBuffer, + _In_opt_ ULONG SizeOfBitMap) +{ + RtlInitializeBitMap(&BitMapHeader->BitMap, BitMapBuffer, SizeOfBitMap); + BitMapHeader->NumberOfSetBits = RtlNumberOfSetBits(&BitMapHeader->BitMap); + BitMapHeader->BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); +} + +static inline +BOOLEAN +RtlAreBitsClearDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlAreBitsClear(&BitMapHeader->BitMap, StartingIndex, Length); +} + +static inline +BOOLEAN +RtlAreBitsSetDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlAreBitsSet(&BitMapHeader->BitMap, StartingIndex, Length); +} + +static inline +VOID +RtlClearAllBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader) +{ + RtlValidateBitmapDbg(BitMapHeader); + RtlClearAllBits(&BitMapHeader->BitMap); + BitMapHeader->NumberOfSetBits = 0; + BitMapHeader->BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); +} + +static inline +VOID +RtlClearBitDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber) +{ + RtlValidateBitmapDbg(BitMapHeader); + if (RtlCheckBit(&BitMapHeader->BitMap, BitNumber) == FALSE) + { + BitMapHeader->NumberOfSetBits--; + } + RtlClearBit(&BitMapHeader->BitMap, BitNumber); + BitMapHeader->BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); +} + +static inline +VOID +RtlClearBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToClear) ULONG StartingIndex, + _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToClear) +{ + RtlValidateBitmapDbg(BitMapHeader); + RtlClearBits(&BitMapHeader->BitMap, StartingIndex, NumberToClear); + BitMapHeader->NumberOfSetBits = RtlNumberOfSetBits(&BitMapHeader->BitMap); + BitMapHeader->BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); +} + +static inline +ULONG +RtlFindClearBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindClearBits(&BitMapHeader->BitMap, NumberToFind, HintIndex); +} + +static inline +ULONG +RtlFindClearBitsAndSetDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindClearBitsAndSet(&BitMapHeader->BitMap, NumberToFind, HintIndex); +} + +static inline +ULONG +RtlFindFirstRunClearDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _Out_ PULONG StartingIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindFirstRunClear(&BitMapHeader->BitMap, StartingIndex); +} + +static inline +ULONG +RtlFindClearRunsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _Out_writes_to_(SizeOfRunArray, return) PRTL_BITMAP_RUN RunArray, + _In_range_(>, 0) ULONG SizeOfRunArray, + _In_ BOOLEAN LocateLongestRuns) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindClearRuns(&BitMapHeader->BitMap, RunArray, SizeOfRunArray, LocateLongestRuns); +} + +static inline +ULONG +RtlFindLastBackwardRunClearDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG FromIndex, + _Out_ PULONG StartingRunIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindLastBackwardRunClear(&BitMapHeader->BitMap, FromIndex, StartingRunIndex); +} + +static inline +ULONG +RtlFindLongestRunClearDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _Out_ PULONG StartingIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindLongestRunClear(&BitMapHeader->BitMap, StartingIndex); +} + +static inline +ULONG +RtlFindNextForwardRunClearDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG FromIndex, + _Out_ PULONG StartingRunIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindNextForwardRunClear(&BitMapHeader->BitMap, FromIndex, StartingRunIndex); +} + +static inline +ULONG +RtlFindNextForwardRunSetDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG FromIndex, + _Out_ PULONG StartingRunIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindNextForwardRunSet(&BitMapHeader->BitMap, FromIndex, StartingRunIndex); +} + +static inline +ULONG +RtlFindSetBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindSetBits(&BitMapHeader->BitMap, NumberToFind, HintIndex); +} + +static inline +ULONG +RtlFindSetBitsAndClearDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlFindSetBitsAndClear(&BitMapHeader->BitMap, NumberToFind, HintIndex); +} + +static inline +ULONG +RtlNumberOfClearBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlNumberOfClearBits(&BitMapHeader->BitMap); +} + +static inline +ULONG +RtlNumberOfSetBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlNumberOfSetBits(&BitMapHeader->BitMap); +} + +static inline +VOID +RtlSetBitDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber) +{ + RtlValidateBitmapDbg(BitMapHeader); + if (RtlCheckBit(&BitMapHeader->BitMap, BitNumber) == FALSE) + { + BitMapHeader->NumberOfSetBits++; + } + RtlSetBit(&BitMapHeader->BitMap, BitNumber); + BitMapHeader->BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); +} + +static inline +VOID +RtlSetBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToSet) ULONG StartingIndex, + _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToSet) +{ + RtlValidateBitmapDbg(BitMapHeader); + RtlSetBits(&BitMapHeader->BitMap, StartingIndex, NumberToSet); + BitMapHeader->NumberOfSetBits = RtlNumberOfSetBits(&BitMapHeader->BitMap); + BitMapHeader->BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); +} + +static inline +VOID +RtlSetAllBitsDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader) +{ + RtlValidateBitmapDbg(BitMapHeader); + RtlSetAllBits(&BitMapHeader->BitMap); + BitMapHeader->NumberOfSetBits = BitMapHeader->BitMap.SizeOfBitMap; + BitMapHeader->BitmapHash = RtlComputeBitmapHashDbg(BitMapHeader); +} + +_Must_inspect_result_ +static inline +BOOLEAN +RtlTestBitDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlTestBit(&BitMapHeader->BitMap, BitNumber); +} + +_Must_inspect_result_ +static inline +BOOLEAN +RtlCheckBitDbg( + _In_ PRTL_BITMAP_DBG BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitPosition) +{ + RtlValidateBitmapDbg(BitMapHeader); + return RtlCheckBit(&BitMapHeader->BitMap, BitPosition); +} + +#define _RTL_BITMAP _RTL_BITMAP_DBG +#define RTL_BITMAP RTL_BITMAP_DBG +#define PRTL_BITMAP PRTL_BITMAP_DBG + +#define RtlInitializeBitMap RtlInitializeBitMapDbg +#define RtlAreBitsClear RtlAreBitsClearDbg +#define RtlAreBitsSet RtlAreBitsSetDbg +#define RtlClearAllBits RtlClearAllBitsDbg +#define RtlClearBit RtlClearBitDbg +#define RtlClearBits RtlClearBitsDbg +#define RtlFindClearBits RtlFindClearBitsDbg +#define RtlFindClearBitsAndSet RtlFindClearBitsAndSetDbg +#define RtlFindFirstRunClear RtlFindFirstRunClearDbg +#define RtlFindClearRuns RtlFindClearRunsDbg +#define RtlFindLastBackwardRunClear RtlFindLastBackwardRunClearDbg +#define RtlFindLongestRunClear RtlFindLongestRunClearDbg +#define RtlFindNextForwardRunClear RtlFindNextForwardRunClearDbg +#define RtlFindNextForwardRunSet RtlFindNextForwardRunSetDbg +#define RtlFindSetBits RtlFindSetBitsDbg +#define RtlFindSetBitsAndClear RtlFindSetBitsAndClearDbg +#define RtlNumberOfClearBits RtlNumberOfClearBitsDbg +#define RtlNumberOfSetBits RtlNumberOfSetBitsDbg +#define RtlSetBit RtlSetBitDbg +#define RtlSetBits RtlSetBitsDbg +#define RtlSetAllBits RtlSetAllBitsDbg +#define RtlTestBit RtlTestBitDbg +#undef RtlCheckBit +#define RtlCheckBit RtlCheckBitDbg