#include #include #include #include BOOLEAN DebugFlag; PVOID HeapHandle; PVOID TestAlloc( IN ULONG Size ) { PVOID a; if ((a = RtlAllocateHeap( HeapHandle, 0, Size )) == NULL) { RtlValidateHeap( HeapHandle, TRUE ); DbgPrint( "\nUHEAP: RtlAllocateHeap( %lx ) failed\n", Size ); DbgBreakPoint(); NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL ); } if (DebugFlag) { DbgPrint( "\n" ); DbgPrint( "\nRtlAllocateHeap( %lx ) => %lx\n", Size, a ); } if (!RtlValidateHeap( HeapHandle, DebugFlag )) { NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL ); } return( a ); } PVOID TestFree( IN PVOID BaseAddress, IN ULONG Size ) { PVOID a; if ((a = RtlFreeHeap( HeapHandle, 0, BaseAddress )) != NULL) { DbgPrint( "\nUHEAP: RtlFreeHeap( %lx ) failed\n", BaseAddress ); RtlValidateHeap( HeapHandle, TRUE ); DbgBreakPoint(); NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL ); } if (DebugFlag) { DbgPrint( "\n" ); DbgPrint( "\nRtlFreeHeap( %lx ) => %lx\n", BaseAddress, a ); } if (!RtlValidateHeap( HeapHandle, DebugFlag )) { NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL ); } return( a ); } BOOLEAN TestHeap( IN PVOID UserHeapBase, IN BOOLEAN Serialize, IN BOOLEAN Sparse, IN ULONG GrowthThreshold, IN ULONG InitialSize ) { PVOID a1,a2,a3,a4; DWORD Flags; Flags = 0; if (!Serialize) { Flags |= HEAP_NO_SERIALIZE; } if (!Sparse) { Flags |= HEAP_GROWABLE; } HeapHandle = RtlCreateHeap( Flags, UserHeapBase, InitialSize, 0, 0, GrowthThreshold ); if ( HeapHandle == NULL ) { DbgPrint( "UHEAP: RtlCreateHeap failed\n" ); DbgBreakPoint(); goto exit; } if (!RtlValidateHeap( HeapHandle, DebugFlag )) { NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL ); } // // TEST 0: // Allocate and free a large chunk of memory so that the following // tests are valid. // DbgPrint( "UHEAP: Test #0\n" ); a1 = TestAlloc( 4096-16 ); TestFree( a1, 0 ); // // TEST 1: // Allocate three chunks, deallocate the middle one, and reallocate it. // DbgPrint( "UHEAP: Test #1\n" ); a1 = TestAlloc( 16 ); a2 = TestAlloc( 32 ); a3 = TestAlloc( 112 ); TestFree( a2, 32 ); a4 = TestAlloc( 32 ); // // TEST 2: // Deallocate first chunk and reallocate it. // DbgPrint( "UHEAP: Test #2\n" ); TestFree( a1, 16 ); a4 = TestAlloc( 16 ); // // TEST 3: // Deallocate last chunk and reallocate it. // DbgPrint( "UHEAP: Test #3\n" ); TestFree( a3, 112 ); a4 = TestAlloc( 112 ); // // TEST 4: // Deallocate last chunk and reallocate larger one. // DbgPrint( "UHEAP: Test #4\n" ); TestFree( a4, 112 ); a4 = TestAlloc( 112+64 ); // // TEST 5: // Deallocate first two chunks and reallocate combined one. // DbgPrint( "UHEAP: Test #5\n" ); TestFree( a1, 16 ); TestFree( a2, 32 ); a4 = TestAlloc( 16+32-4 ); // // TEST 6: // There should be room between blocks 2 and 3 for a small allocation. // Make sure zero byte allocations work. // DbgPrint( "UHEAP: Test #6\n" ); a4 = TestAlloc( 0 ); // // TEST 7: // Deallocate last two chunks and reallocate one. Address should change. // DbgPrint( "UHEAP: Test #7\n" ); TestFree( a3, 112+64 ); TestFree( a4, 0 ); a3 = TestAlloc( 112 ); // // TEST 8: // Deallocate everything and make sure it can be reallocated. // DbgPrint( "UHEAP: Test #8\n" ); TestFree( a1, 16+32-4 ); TestFree( a3, 112 ); a2 = TestAlloc( 200 ); // // TEST 9: // Allocate more than is committed. // DbgPrint( "UHEAP: Test #9\n" ); a1 = TestAlloc( 100000 ); TestFree( a2, 200 ); TestFree( a1, 100000 ); // // TEST 10: // Allocate more than maximum size of heap // DbgPrint( "UHEAP: Test #10\n" ); a3 = TestAlloc( 100000 ); TestFree( a3, 100000 ); // // TEST 11: // Destroy the heap // DbgPrint( "UHEAP: Test #11\n" ); HeapHandle = RtlDestroyHeap( HeapHandle ); if ( HeapHandle != NULL ) { DbgPrint( "UHEAP: RtlDestroyHeap failed\n" ); DbgBreakPoint(); goto exit; } return( TRUE ); exit: if (HeapHandle != NULL) { HeapHandle = RtlDestroyHeap( HeapHandle ); } return( FALSE ); } VOID Usage( VOID ) { DbgPrint( "Usage: UHEAP [-s ReserveSize] | [-g InitialSize GrowthThreshold]\n" ); (VOID)NtTerminateProcess( NtCurrentProcess(), STATUS_UNSUCCESSFUL ); } NTSTATUS main( int argc, char *argv[], char *envp[], ULONG DebugParameter OPTIONAL ) { NTSTATUS Status; PCH s; PVOID UserHeapBase = NULL; BOOLEAN Serialize = FALSE; BOOLEAN Sparse = FALSE; ULONG GrowthThreshold = 0; ULONG InitialSize = 0x8000; DebugFlag = DebugParameter; DbgPrint( "** Start of User Mode Test of RtlAllocateHeap/RtlFreeHeap **\n" ); while (--argc) { s = *++argv; if (*s == '-') { switch( *++s ) { case 'x': case 'X': Serialize = TRUE; break; case 's': case 'S': Sparse = TRUE; if (--argc) { InitialSize = atoi( *++argv ); Status = NtAllocateVirtualMemory( NtCurrentProcess(), (PVOID *)&UserHeapBase, 0, &InitialSize, MEM_RESERVE, PAGE_READWRITE ); if (!NT_SUCCESS( Status )) { DbgPrint( "UHEAP: Unable to allocate heap - 0x%lx bytes\n", InitialSize ); Usage(); } } else { Usage(); } break; case 'g': case 'G': if (argc >= 2) { argc -= 2; InitialSize = atoi( *++argv ); GrowthThreshold = atoi( *++argv ); } else { Usage(); } break; default: Usage(); } } else { Usage(); } } TestHeap( UserHeapBase, Serialize, Sparse, GrowthThreshold, InitialSize ); if (UserHeapBase != NULL) { Status = NtFreeVirtualMemory( NtCurrentProcess(), (PVOID *)&UserHeapBase, &InitialSize, MEM_RELEASE ); } DbgPrint( "** End of User Mode Test of RtlAllocateHeap/RtlFreeHeap **\n" ); (VOID)NtTerminateProcess( NtCurrentProcess(), STATUS_SUCCESS ); return STATUS_SUCCESS; }