/** @file File for memory allocation tracking functions. Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "MyAlloc.h" #if USE_MYALLOC // // Get back to original alloc/free calls. // #undef malloc #undef calloc #undef realloc #undef free // // Start of allocation list. // STATIC MY_ALLOC_STRUCT *MyAllocData = NULL; // // // STATIC UINT32 MyAllocHeadMagik = MYALLOC_HEAD_MAGIK; STATIC UINT32 MyAllocTailMagik = MYALLOC_TAIL_MAGIK; /** Check for corruptions in the allocated memory chain. If a corruption is detection program operation stops w/ an exit(1) call. @param Final When FALSE, MyCheck() returns if the allocated memory chain has not been corrupted. When TRUE, MyCheck() returns if there are no un-freed allocations. If there are un-freed allocations, they are displayed and exit(1) is called. @param File Set to __FILE__ by macro expansion. @param Line Set to __LINE__ by macro expansion. **/ VOID MyCheck ( BOOLEAN Final, UINT8 File[], UINTN Line ) { MY_ALLOC_STRUCT *Tmp; // // Check parameters. // if (File == NULL) { printf ( "\nMyCheck(Final=%u, File=NULL, Line=%u)" "Invalid parameter(s).\n", Final, (unsigned)Line ); exit (1); } if (Line == 0) { printf ( "\nMyCheck(Final=%u, File=%s, Line=%u)" "Invalid parameter(s).\n", Final, File, (unsigned)Line ); exit (1); } if (strlen ((CHAR8 *)File) == 0) { printf ( "\nMyCheck(Final=%u, File=%s, Line=%u)" "Invalid parameter.\n", Final, File, (unsigned)Line ); exit (1); } // // Check structure contents. // for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { if (memcmp(Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik) || memcmp(&Tmp->Buffer[Tmp->Size + sizeof(UINT32)], &MyAllocTailMagik, sizeof MyAllocTailMagik)) { break; } } // // If Tmp is not NULL, the structure is corrupt. // if (Tmp != NULL) { printf ( "\nMyCheck(Final=%u, File=%s, Line=%u)""\nStructure corrupted!" "\nFile=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", Final, File, (unsigned)Line, Tmp->File, (unsigned) Tmp->Line, (unsigned) Tmp->Size, (unsigned) *(UINT32 *) (Tmp->Buffer), (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) ); exit (1); } // // If Final is TRUE, display the state of the structure chain. // if (Final) { if (MyAllocData != NULL) { printf ( "\nMyCheck(Final=%u, File=%s, Line=%u)" "\nSome allocated items have not been freed.\n", Final, File, (unsigned)Line ); for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { printf ( "File=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", Tmp->File, (unsigned) Tmp->Line, (unsigned) Tmp->Size, (unsigned) *(UINT32 *) (Tmp->Buffer), (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) ); } } } } /** Allocate a new link in the allocation chain along with enough storage for the File[] string, requested Size and alignment overhead. If memory cannot be allocated or the allocation chain has been corrupted, exit(1) will be called. @param Size Number of bytes (UINT8) requested by the called. Size cannot be zero. @param File Set to __FILE__ by macro expansion. @param Line Set to __LINE__ by macro expansion. @return Pointer to the caller's buffer. **/ VOID * MyAlloc ( UINTN Size, UINT8 File[], UINTN Line ) { MY_ALLOC_STRUCT *Tmp; UINTN Len; // // Check for invalid parameters. // if (File == NULL) { printf ( "\nMyAlloc(Size=%u, File=NULL, Line=%u)" "\nInvalid parameter(s).\n", (unsigned)Size, (unsigned)Line ); exit (1); } if (Size == 0 || Line == 0) { printf ( "\nMyAlloc(Size=%u, File=%s, Line=%u)" "\nInvalid parameter(s).\n", (unsigned)Size, File, (unsigned)Line ); exit (1); } Len = strlen ((CHAR8 *)File); if (Len == 0) { printf ( "\nMyAlloc(Size=%u, File=%s, Line=%u)" "\nInvalid parameter.\n", (unsigned)Size, File, (unsigned)Line ); exit (1); } // // Check the allocation list for corruption. // MyCheck (0, (UINT8 *)__FILE__, __LINE__); // // Allocate a new entry. // Tmp = calloc ( 1, sizeof (MY_ALLOC_STRUCT) + Len + 1 + sizeof (UINT64) + Size + (sizeof MyAllocHeadMagik) + (sizeof MyAllocTailMagik) ); if (Tmp == NULL) { printf ( "\nMyAlloc(Size=%u, File=%s, Line=%u)" "\nOut of memory.\n", (unsigned)Size, File, (unsigned)Line ); exit (1); } // // Fill in the new entry. // Tmp->File = ((UINT8 *) Tmp) + sizeof (MY_ALLOC_STRUCT); strcpy ((CHAR8 *)Tmp->File, (CHAR8 *)File); Tmp->Line = Line; Tmp->Size = Size; Tmp->Buffer = (UINT8 *) (((UINTN) Tmp + Len + 9) &~7); memcpy (Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik); memcpy ( &Tmp->Buffer[Size + sizeof (UINT32)], &MyAllocTailMagik, sizeof MyAllocTailMagik ); Tmp->Next = MyAllocData; Tmp->Cksum = (UINTN) Tmp + (UINTN) (Tmp->Next) + Tmp->Line + Tmp->Size + (UINTN) (Tmp->File) + (UINTN) (Tmp->Buffer); MyAllocData = Tmp; return Tmp->Buffer + sizeof (UINT32); } /** This does a MyAlloc(), memcpy() and MyFree(). There is no optimization for shrinking or expanding buffers. An invalid parameter will cause MyRealloc() to fail with a call to exit(1). @param Ptr Pointer to the caller's buffer to be re-allocated. @param Size Size of new buffer. Size cannot be zero. @param File Set to __FILE__ by macro expansion. @param Line Set to __LINE__ by macro expansion. @return Pointer to new caller's buffer. **/ VOID * MyRealloc ( VOID *Ptr, UINTN Size, UINT8 File[], UINTN Line ) { MY_ALLOC_STRUCT *Tmp; VOID *Buffer; // // Check for invalid parameter(s). // if (File == NULL) { printf ( "\nMyRealloc(Ptr=%p, Size=%u, File=NULL, Line=%u)" "\nInvalid parameter(s).\n", Ptr, (unsigned)Size, (unsigned)Line ); exit (1); } if (Size == 0 || Line == 0) { printf ( "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" "\nInvalid parameter(s).\n", Ptr, (unsigned)Size, File, (unsigned)Line ); exit (1); } if (strlen ((CHAR8 *)File) == 0) { printf ( "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" "\nInvalid parameter.\n", Ptr, (unsigned)Size, File, (unsigned)Line ); exit (1); } // // Find existing buffer in allocation list. // if (Ptr == NULL) { Tmp = NULL; } else if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { Tmp = MyAllocData; } else { for (Tmp = MyAllocData;; Tmp = Tmp->Next) { if (Tmp->Next == NULL) { printf ( "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" "\nCould not find buffer.\n", Ptr, (unsigned)Size, File, (unsigned)Line ); exit (1); } Tmp = Tmp->Next; } } // // Allocate new buffer, copy old data, free old buffer. // Buffer = MyAlloc (Size, File, Line); if (Buffer != NULL && Tmp != NULL) { memcpy ( Buffer, &Tmp->Buffer[sizeof (UINT32)], ((Size <= Tmp->Size) ? Size : Tmp->Size) ); MyFree (Ptr, (UINT8 *)__FILE__, __LINE__); } return Buffer; } /** Release a previously allocated buffer. Invalid parameters will cause MyFree() to fail with an exit(1) call. @param Ptr Pointer to the caller's buffer to be freed. A NULL pointer will be ignored. @param File Set to __FILE__ by macro expansion. @param Line Set to __LINE__ by macro expansion. **/ VOID MyFree ( VOID *Ptr, UINT8 File[], UINTN Line ) { MY_ALLOC_STRUCT *Tmp; MY_ALLOC_STRUCT *Tmp2; // // Check for invalid parameter(s). // if (File == NULL) { printf ( "\nMyFree(Ptr=%p, File=NULL, Line=%u)" "\nInvalid parameter(s).\n", Ptr, (unsigned)Line ); exit (1); } if (Line == 0) { printf ( "\nMyFree(Ptr=%p, File=%s, Line=%u)" "\nInvalid parameter(s).\n", Ptr, File, (unsigned)Line ); exit (1); } if (strlen ((CHAR8 *)File) == 0) { printf ( "\nMyFree(Ptr=%p, File=%s, Line=%u)" "\nInvalid parameter.\n", Ptr, File, (unsigned)Line ); exit (1); } // // Freeing NULL is always valid. // if (Ptr == NULL) { return ; } // // Fail if nothing is allocated. // if (MyAllocData == NULL) { printf ( "\nMyFree(Ptr=%p, File=%s, Line=%u)" "\nCalled before memory allocated.\n", Ptr, File, (unsigned)Line ); exit (1); } // // Check for corrupted allocation list. // MyCheck (0, (UINT8 *)__FILE__, __LINE__); // // Need special check for first item in list. // if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { // // Unlink first item in list. // Tmp = MyAllocData; MyAllocData = MyAllocData->Next; } else { // // Walk list looking for matching item. // for (Tmp = MyAllocData;; Tmp = Tmp->Next) { // // Fail if end of list is reached. // if (Tmp->Next == NULL) { printf ( "\nMyFree(Ptr=%p, File=%s, Line=%u)\n" "\nNot found.\n", Ptr, File, (unsigned)Line ); exit (1); } // // Leave loop when match is found. // if (&Tmp->Next->Buffer[sizeof (UINT32)] == Ptr) { break; } } // // Unlink item from list. // Tmp2 = Tmp->Next; Tmp->Next = Tmp->Next->Next; Tmp = Tmp2; } // // Release item. // free (Tmp); } #endif /* USE_MYALLOC */ /* eof - MyAlloc.c */