/*++ 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