/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    rxcemm.c

Abstract:

    This module contains the NT implementation of memory management for RxCe.

Notes:


--*/

#include "precomp.h"
#pragma  hdrstop
#include "rxtdip.h"

//
//  The debug trace level
//

#define Dbg                              (DEBUG_TRACE_RXCEPOOL)

#define RXCE_ZONE_ALLOCATION 0x80

//
// Pool debugging data structures.
//
LIST_ENTRY s_RxMdlList;

// MDL debugging structures.

typedef struct _WRAPPED_RX_MDL {
    LIST_ENTRY  Next;
    PUCHAR      File;
    int         Line;
    PMDL        pMdl;
} WRAPPED_RX_MDL, *PWRAPPED_RX_MDL;

//
// Pool header data structure.  Ensure it is 8 byte aligned, no
// matter what members are added to the pool header
//
typedef struct _RX_POOL_HEADER {
    union {
        struct _RXH {
            BYTE  Signature[ 16 ];
            ULONG Size;
            ULONG Type;
            PSZ   AFileName;
            ULONG ALineNumber;
            PSZ   FFileName;
            ULONG FLineNumber;
        };
        UCHAR _pad[ (sizeof( struct _RXH ) + 7) & (~7) ];
    };
} RX_POOL_HEADER, *PRX_POOL_HEADER;

//
// Number of trailer bytes after a pool allocation with a known signature
//
#define TRAIL_BYTES  16

#ifdef RX_POOL_WRAPPER

PVOID
_RxAllocatePoolWithTag(
    ULONG Type,
    ULONG Size,
    ULONG Tag,
    PSZ   FileName,
    ULONG LineNumber
    )
/*++

Routine Description:

    This routine allocates the desired pool and sets up the debugging header and trailer
    to catch most instances of memory trashing

Arguments:

    Type    - type of pool to be allocated

    Size    - size of the allocation

Return Value:

    a valid pointer if successful, otherwise FALSE.

--*/
{
#if 0
    PCHAR pBuffer;
    PRX_POOL_HEADER pPoolHeader;

    ASSERT( Size != 0 );
    ASSERT(
        Type == PagedPool ||
        Type == (PagedPool | POOL_COLD_ALLOCATION) ||
        Type == NonPagedPool);

    ASSERT( (sizeof(RX_POOL_HEADER)&7) == 0  );

    pPoolHeader = ExAllocatePoolWithTagPriority(
                      Type,
                      sizeof( *pPoolHeader ) + Size + TRAIL_BYTES,
                      Tag,
                      LowPoolPriority);

    if ( pPoolHeader == NULL ) {
        RxLog(("RA:NULL %d %d %s\n", Type, LineNumber, &FileName[24]));
        return( NULL );
    }

    //
    // Fill the head so we can verify valid free's
    //
    RtlFillMemory( pPoolHeader->Signature, sizeof( pPoolHeader->Signature ), 'H' );
    pPoolHeader->Size = Size;
    pPoolHeader->Type = Type;
    pPoolHeader->AFileName = FileName;
    pPoolHeader->ALineNumber = LineNumber;
    pPoolHeader->FFileName = NULL;
    pPoolHeader->FLineNumber = 0;

    pBuffer = (PCHAR)(pPoolHeader + 1);

    //
    // Fill the memory to catch uninitialized structures, etc
    //
    RtlFillMemory( pBuffer, Size, '*' );

    //
    // Fill the tail to catch overruns
    //
    RtlFillMemory( pBuffer + Size, TRAIL_BYTES, 'T' );

    //
    // Make sure we're starting out valid
    //
    RxCheckMemoryBlock( pBuffer );

    return( pBuffer );
#endif

    return ExAllocatePoolWithTagPriority(
               Type,Size,Tag,LowPoolPriority);
}

VOID
_RxFreePool( PVOID pBuffer, PSZ FileName, ULONG LineNumber )
{
#if 0
    if( _RxCheckMemoryBlock( pBuffer, FileName, LineNumber ) ) {

        PRX_POOL_HEADER pPoolHeader = ((PRX_POOL_HEADER)pBuffer) - 1;

        //
        // Zap the block, to catch cases where we are using freed blocks
        //
        RtlFillMemory( pPoolHeader->Signature,
                      sizeof( pPoolHeader->Signature ),
                     'F' );

        pPoolHeader->FFileName = FileName;
        pPoolHeader->FLineNumber = LineNumber;
        RtlFillMemory( pPoolHeader+1,
                      pPoolHeader->Size + TRAIL_BYTES,
                     'F' );

        ExFreePool( pPoolHeader );
    }
#endif

    ExFreePool(pBuffer);
}

BOOLEAN
_RxCheckMemoryBlock(
    PVOID pBuffer,
    PSZ   FileName,
    ULONG LineNumber
    )
/*++

Routine Description:

    This routine frees up the pool allocated through RxAllocate

Arguments:

    pv       - the block to be freed

--*/
{
    PRX_POOL_HEADER pPoolHeader = ((PRX_POOL_HEADER)pBuffer) - 1;
    PCHAR pTail;
    ULONG i;

    if( pBuffer == NULL ) {
        DbgPrint( "RxCheckMemoryBlock( NULL ) at %s %d\n",
                   FileName, LineNumber );
        DbgBreakPoint();
        return FALSE;
    }

    //
    // Make sure we have a valid block
    //
    for( i=0; i < sizeof( pPoolHeader->Signature ); i++ ) {
        if( pPoolHeader->Signature[i] != 'H' ) {
            if( pPoolHeader->Signature[i] == 'F' && i == 0 ) {
                DbgPrint( "RxFreePool: Likely double free on block at %X\n", pPoolHeader );
            }

            DbgPrint( "RxCheckMemoryBlock: Invalid header signature for block %X\n", pPoolHeader );
            DbgPrint( "            Called from %s %d\n", FileName, LineNumber );
            DbgPrint( "            Originally Freed at %s %d\n",pPoolHeader->FFileName,pPoolHeader->FLineNumber);
            DbgPrint( "            Size is x%X, user part at %X\n", pPoolHeader->Size, pPoolHeader + 1 );
            DbgBreakPoint();
            return FALSE;
        }
    }

    if( pPoolHeader->Type != PagedPool && 
        pPoolHeader->Type != (PagedPool | POOL_COLD_ALLOCATION) &&
        pPoolHeader->Type != NonPagedPool) {
        DbgPrint( "RxCheckMemoryBlock:\n" );
        DbgPrint( "    Invalid PoolHeader->Type for block %X\n", pPoolHeader );
        DbgPrint( "    Called from %s %d\n", FileName, LineNumber );
        DbgBreakPoint();
        return FALSE;
    }

    if( pPoolHeader->Size == 0 ) {
        DbgPrint( "RxCheckMemoryBlock:\n" );
        DbgPrint( "     Size is 0 for block %X\n", pPoolHeader );
        DbgPrint( "    Called from %s %d\n", FileName, LineNumber );
        DbgBreakPoint();
        return FALSE;
    }

    //
    // Look to see if the buffer has been overrun
    //
    pTail = (PCHAR)pBuffer + pPoolHeader->Size;
    for( i=0; i < TRAIL_BYTES; i++ ) {
        if( *pTail++ != 'T' ) {
            DbgPrint( "RxCheckMemoryBlock: Overrun memory block at %X\n", pPoolHeader );
            DbgPrint( "            RxCheckMemoryBlock called from %s line %d\n", FileName, LineNumber );
            DbgPrint( "            Allocated at %s line %d\n", pPoolHeader->AFileName, pPoolHeader->ALineNumber );
            DbgPrint( "            Size is x%X, user part at %X\n", pPoolHeader->Size, pPoolHeader + 1 );
            DbgPrint( "            Overrun begins at %X\n", pTail-1 );
            DbgBreakPoint();
            return FALSE;
        }
    }

    return TRUE;
}

#endif


