/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: ntrtlbuffer3.c Abstract: Author: Jay Krell (JayKrell) January 2002 Environment: Revision History: --*/ #include "ntrtlbuffer3.h" typedef struct _REVEAL_RTL_BYTE_BUFFER3 { PREVEAL_RTL_BYTE_BUFFER3 Self; // for heap allocated "mini dynamic" PVOID Buffer; SIZE_T RequestedSize; SIZE_T AllocatedSize; PVOID StaticBuffer; SIZE_T StaticBufferSize; PCRTL_BUFFER3_ALLOCATOR Traits; PVOID TraitsContext; } REVEAL_RTL_BYTE_BUFFER3, *PREVEAL_RTL_BYTE_BUFFER3; typedef const REVEAL_RTL_BYTE_BUFFER3 * PCREVEAL_RTL_BYTE_BUFFER3; PREVEAL_RTL_BYTE_BUFFER3 RtlpRevealByteBuffer3( PRTL_BYTE_BUFFER3 OpaqueBuffer ) { return ((PREVEAL_RTL_BYTE_BUFFER3)OpaqueBuffer)->Self; } RTL_BUFFER3_RETURN FASTCALL RtlInitByteBuffer3( ULONG Flags, SIZE_T SizeofBuffer, PRTL_BYTE_BUFFER3 Buffer, SIZE_T SizeofStaticBuffer, PBYTE StaticBuffer, SIZE_T SizeofTraits, PCRTL_BUFFER3_ALLOCATOR Traits, PVOID TraitsContext ) { RTL_BUFFER3_RETURN Ret; PREVEAL_RTL_BYTE_BUFFER3 Revealed; BOOL NewStaticWithMiniDynamic; if (SizeofBuffer < sizeof(*Buffer)) { if (SizeofBuffer < (sizeof(ULONG_PTR))) { goto InvalidParameter; } if (Traits == NULL) { goto InvalidParameter; } if (!RTL_CONTAINS_FIELD(Traits, SizeofTraits, CanAllocate)) { goto InvalidParameter; } if (!RTL_CONTAINS_FIELD(Traits, SizeofTraits, Allocate)) { goto InvalidParameter; } if (!Traits->CanAllocate(TraitsContext)) { goto InvalidParameter; } NewStaticWithMiniDynamic = (StaticBuffer == NULL && SizeofStaticBuffer != 0); RevealedSize = sizeof(*Revealed; if (NewStaticWithMiniDynamic) { RevealedSize += SizeofStaticBuffer; } Revealed = (PREVEAL_RTL_BYTE_BUFFER3)Traits->Allocate(TraitsContext, RevealedSize); if (Revealed == NULL) { if (NewStaticWithMiniDynamic) { NewStaticWithMiniDynamic = FALSE; Revealed = (PREVEAL_RTL_BYTE_BUFFER3)Traits->Allocate(TraitsContext, sizeof(*Revealed)); } if (Revealed == NULL) { goto CallbackError; } } if (NewStaticWithMiniDynamic) { StaticBuffer = (PBYTE)(Revealed + 1); } } else { Revealed = (PREVEAL_RTL_BYTE_BUFFER3)Buffer; } ((PREVEAL_RTL_BYTE_BUFFER3)OpaqueBuffer)->Self = Revealed; Revealed->StaticBuffer = StaticBuffer; Revealed->StaticBufferSize = SizeofStaticBuffer; Revealed->RequestedSize = 0; Revealed->AllocatedSize = SizeofStaticBuffer; Revealed->Buffer = StaticBuffer; Revealed->Traits = Traits; Revealed->TraitsContext = TraitsContext; Ret = RTL_BUFFER3_SUCCESS; Exit: return Ret; InvalidParameter: Ret = RTL_BUFFER3_INVALID_PARAMETER; goto Exit; CallbackError: Ret = RTL_BUFFER3_CALLBACK_ERROR; goto Exit; } BOOL FASTCALL RtlBuffer3Allocator_CanAllocate_False(PVOID VoidContext) { return FALSE; } BOOL FASTCALL RtlBuffer3Allocator_CanAllocate_True(PVOID VoidContext) { return TRUE; } BOOL FASTCALL RtlBuffer3Allocator_CanReallocate_False(PVOID VoidContext) { return FALSE; } BOOL FASTCALL RtlBuffer3Allocator_CanReallocate_True(PVOID VoidContext) { return TRUE; } #if defined(_WINBASE_) #define RtlpBuffer3Allocator_Win32HeapGetHeap(c) \ (((c) != NULL && (c)->UsePrivateHeap) ? (c)->PrivateHeap : GetProcessHeap()) #define RtlpBuffer3Allocator_Win32HeapGetError(c) \ (((c) != NULL && (c)->UsePrivateError) ? (c)->PrivateOutOfMemoryError : ERROR_NO_MEMORY) #define RtlpBuffer3Allocator_Win32HeapGetFlags(c) \ (((c) != NULL) ? (c)->HeapFlags : 0) #define RtlpBuffer3Allocator_Win32HeapSetLastError(c) \ (((c) == NULL || (c)->DoNotSetLastError) ? ((void)0) : SetLastError(RtlpBuffer3Allocator_Win32HeapGetError(c))) PVOID FASTCALL RtlBuffer3Allocator_Win32HeapAllocate(PVOID VoidContext, SIZE_T NumberOfBytes) { PVOID p; PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; p = HeapAlloc(RtlpBuffer3Allocator_Win32HeapGetHeap(Context), RtlpBuffer3Allocator_Win32HeapGetFlags(Context), NumberOfBytes); if (p == NULL) RtlpBuffer3Allocator_Win32HeapSetLastError(Context); return p; } VOID FASTCALL RtlBuffer3Allocator_Win32HeapFree(PVOID VoidContext, PVOID Pointer); { PVOID p; PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; HeapFree(RtlpBuffer3Allocator_Win32HeapGetHeap(Context), RtlpBuffer3Allocator_Win32HeapGetFlags(Context), Pointer); } PVOID FASTCALL RtlBuffer3Allocator_Win32HeapReallocate(PVOID VoidContext, PVOID OldPointer, SIZE_T NewSize) { PVOID p; PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; p = HeapReAlloc(RtlpBuffer3Allocator_Win32HeapGetHeap(Context), RtlpBuffer3Allocator_Win32HeapGetFlags(Context), OldPointer, NewSize); if (p == NULL) RtlpBuffer3Allocator_Win32HeapSetLastError(Context); return p; } #endif #if defined(_NTRTL_) || defined(_NTURTL_) #if RTLBUFFER3_KERNELMODE #define RtlpBuffer3Allocator_NtHeapGetHeap(c) \ (ASSERT((c) != NULL), ASSERT((c)->UsePrivateHeap), ASSERT((c)->PrivateHeap != NULL), (c)->PrivateHeap) #define RtlpBuffer3Allocator_NtHeapGetFlags(c) \ (ASSERT((c) != NULL), (c)->HeapFlags) #else #define RtlpBuffer3Allocator_NtHeapGetHeap(c) \ (((c) != NULL && (c)->UsePrivateHeap) ? (c)->PrivateHeap : RtlProcessHeap()) #define RtlpBuffer3Allocator_NtHeapGetFlags(c) \ (((c) != NULL) ? (c)->HeapFlags : 0) #endif PVOID FASTCALL RtlBuffer3Allocator_NtHeapAllocate(PVOID VoidContext, SIZE_T NumberOfBytes) { PVOID p; PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; p = RtlAllocateHeap(RtlpBuffer3Allocator_NtHeapGetHeap(Context), RtlpBuffer3Allocator_NtHeapGetFlags(Context), NumberOfBytes); return p; } VOID FASTCALL RtlBuffer3Allocator_NtHeapFree(PVOID VoidContext, PVOID Pointer); { PVOID p; PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; RtlFreeHeap(RtlpBuffer3Allocator_NtHeapGetHeap(Context), RtlpBuffer3Allocator_NtHeapGetFlags(Context), Pointer); } PVOID FASTCALL RtlBuffer3Allocator_NtHeapReallocate(PVOID VoidContext, PVOID OldPointer, SIZE_T NewSize) { #if RTLBUFFER3_KERNELMODE || !defined(_NTURTL_) return NULL; #else PVOID p; PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; p = RtlReAllocateHeap(RtlpBuffer3Allocator_NtHeapGetHeap(Context), RtlpBuffer3Allocator_NtHeapGetFlags(Context), OldPointer, NewSize); return p; #endif } #endif SIZE_T FASTCALL * RtlBuffer3Allocator_FixedAllocationSize(PVOID VoidContext, SIZE_T CurrentAllocatedSize, SIZE_T RequiredSize) { return CurrentAllocatedSize; } SIZE_T FASTCALL * RtlBuffer3Allocator_DoublingAllocationSize(PVOID VoidContext, SIZE_T CurrentAllocatedSize, SIZE_T RequiredSize) { CurrentAllocatedSize += CurrentAllocatedSize; return (RequiredSize >= CurrentAllocatedSize) ? RequiredSize : CurrentAllocatedSize; } SIZE_T FASTCALL * RtlBuffer3Allocator_MinimumAlocationSize(PVOID VoidContext, SIZE_T CurrentAllocatedSize, SIZE_T RequiredSize) { return RequiredSize; } // // RtlAllocateStringRoutine is not exported outside of ntoskrnl.exe and ntdll.dll. // RtlFreeStringRoutine is exported directly enough via RtlFreeUnicodeString. // // see base\ntdll\ldrinit.c and base\ntos\ex\pool.c for the definitions // of RtlAllocateStringRoutine and RtlFreeStringRoutine. // VOID FASTCALL RtlBuffer3Allocator_NtStringFree(PVOID VoidContext, PVOID Pointer) { UNICODE_STRING UnicodeString; UnicodeString.Buffer = (PWSTR)Pointer; RtlFreeUnicodeString(&UnicodeString); } #if RTLBUFFER3_NTKERNEL || RTLBUFFER3_NTDLL PVOID FASTCALL RtlBuffer3Allocator_NtStringAllocate(PVOID VoidContext, SIZE_T NumberOfBytes) { return (*RtlAllocateStringRoutine)(NumberOfBytes); } #elif RTLBUFFER3_USERMODE PVOID FASTCALL RtlBuffer3Allocator_NtStringAllocate(PVOID VoidContext, SIZE_T NumberOfBytes) { return RtlAllocateHeap(RtlProcessHeap(), 0, NumberOfBytes); } #elif RTLBUFFER3_KERNELMODE PVOID FASTCALL RtlBuffer3Allocator_NtStringAllocate(PVOID VoidContext, SIZE_T NumberOfBytes) { #undef ExAllocatePoolWithTag return ExAllocatePoolWithTag(PagedPool,NumberOfBytes,'grtS'); } #endif #if RTLBUFFER3_KERNELMODE && (defined(_EX_) || defined(_NTDDK_) || defined(_NTIFS_) || defined(_NTOSP_) || defined(_WDM_) || defined(_NTHAL_)) #define RtlpBuffer3Allocator_NtkernelPool_GetWhichFunction(c) \ (((c) != NULL) ? (c)->WhichFunction : RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL) #define RtlpBuffer3Allocator_NtkernelPool_GetTag(c) \ (((c) != NULL) ? (c)->Tag : 0) #define RtlpBuffer3Allocator_NtkernelPool_GetType(c) \ (((c) != NULL) ? (c)->Type : NonPagedPool) #define RtlpBuffer3Allocator_NtkernelPool_GetPriority(c) \ (((c) != NULL) ? (c)->Priority : NormalPoolPriority) #undef ExAllocatePoolWithTag #undef ExAllocatePool #undef ExAllocatePoolWithQuota #undef ExAllocatePoolWithQuotaTag #undef ExFreePool #undef ExFreePoolWithTag PVOID FASTCALL RtlBuffer3Allocator_NtkernelPoolAllocate(PVOID VoidContext, SIZE_T NumberOfBytes) { PVOID p; PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; switch (RtlpBuffer3Allocator_NtkernelPool_GetWhichFunction(Context)) { default: case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL: p = ExAllocatePool( RtlpBuffer3Allocator_NtkernelPool_GetType(Context), NumberOfBytes ); break; case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_TAG: p = ExAllocatePoolWithTag( RtlpBuffer3Allocator_NtkernelPool_GetType(Context), NumberOfBytes, RtlpBuffer3Allocator_NtkernelPool_GetTag(Context) ); break; case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_QUOTA: p = ExAllocatePoolWithQuota( RtlpBuffer3Allocator_NtkernelPool_GetType(Context), NumberOfBytes ); break; case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_QUOTA_TAG: p = ExAllocatePoolWithQuotaTag( RtlpBuffer3Allocator_NtkernelPool_GetType(Context), NumberOfBytes, RtlpBuffer3Allocator_NtkernelPool_GetTag(Context) ); break; case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_TAG_PRIORITY: p = ExAllocatePoolWithTagPriority( RtlpBuffer3Allocator_NtkernelPool_GetType(Context), NumberOfBytes, RtlpBuffer3Allocator_NtkernelPool_GetTag(Context), RtlpBuffer3Allocator_NtkernelPool_GetPriority(Context) ); break; } return p; } VOID FASTCALL RtlBuffer3Allocator_NtKernelPoolFree(PVOID VoidContext, PVOID Pointer) { PRTL_BUFFER3_ALLOCATOR_WIN32HEAP Context; // // ExFreePool/ExAllocatePoolWithTag, pretty unique among allocators, does not accept NULL. // if (Pointer == NULL) return; Context = (PRTL_BUFFER3_ALLOCATOR_WIN32HEAP)VoidContext; switch (RtlpBuffer3Allocator_NtkernelPool_GetWhichFunction(Context)) { default: case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL: case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_QUOTA: ExFreePool(Pointer); break; case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_TAG: case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_QUOTA_TAG: case RTL_BUFFER3_ALLOCATOR_NTKERNELPOOL_ALLOCATE_EX_ALLOCATE_POOL_WITH_TAG_PRIORITY: ExAllocatePoolWithTag(Pointer); break; } } #endif