summaryrefslogblamecommitdiffstats
path: root/private/urtl/uheap.c
blob: 1cbe7c36be641fa239d3bd8bb124dfe3a69a8299 (plain) (tree)

























































































































































































































































































































































                                                                                       
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>

#include <stdlib.h>

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;
}