Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Files for debugging memory allocator
  23.  *
  24.  *
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include "pstypes.h"
  31. #include "dxxerror.h"
  32. #include "args.h"
  33. #include "console.h"
  34. #include "u_mem.h"
  35. #include <array>
  36.  
  37. namespace dcx {
  38.  
  39. #define MEMSTATS 0
  40. #define FULL_MEM_CHECKING 1
  41.  
  42. #ifdef DEBUG_MEMORY_ALLOCATIONS
  43. #if defined(FULL_MEM_CHECKING)
  44.  
  45. #define CHECKSIZE 16
  46. #define CHECKBYTE 0xFC
  47.  
  48. #define MAX_INDEX 10000
  49.  
  50. static std::array<void *, MAX_INDEX> MallocBase;
  51. static std::array<unsigned int, MAX_INDEX> MallocSize;
  52. static std::array<unsigned char, MAX_INDEX> Present;
  53. static std::array<const char *, MAX_INDEX> Filename;
  54. static std::array<const char *, MAX_INDEX> Varname;
  55. static std::array<int, MAX_INDEX> LineNum;
  56. static int BytesMalloced = 0;
  57.  
  58. static int free_list[MAX_INDEX];
  59.  
  60. static int num_blocks = 0;
  61.  
  62. static int Initialized = 0;
  63. static int LargestIndex = 0;
  64. static int out_of_memory = 0;
  65.  
  66. void mem_init()
  67. {
  68.         Initialized = 1;
  69.  
  70.         MallocBase = {};
  71.         MallocSize = {};
  72.         Present = {};
  73.         Filename = {};
  74.         Varname = {};
  75.         LineNum = {};
  76.         for (int i=0; i<MAX_INDEX; i++ )
  77.         {
  78.                 free_list[i] = i;
  79.         }
  80.  
  81.         num_blocks = 0;
  82.         LargestIndex = 0;
  83.  
  84.         atexit(mem_display_blocks);
  85. }
  86.  
  87. static void PrintInfo( int id )
  88. {
  89.         con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] );
  90. }
  91.  
  92.  
  93. void *mem_malloc(size_t size, const char * var, const char * filename, unsigned line)
  94. {
  95.         int id;
  96.         void *ptr;
  97.         char * pc;
  98.  
  99.         if (Initialized==0)
  100.                 mem_init();
  101.  
  102. #if MEMSTATS
  103.         {
  104.                 unsigned long   theFreeMem = 0;
  105.        
  106.                 if (sMemStatsFileInitialized)
  107.                 {
  108.                         theFreeMem = FreeMem();
  109.                
  110.                         fprintf(sMemStatsFile,
  111.                                         "\n%9u bytes free before attempting: MALLOC %9u bytes.",
  112.                                         theFreeMem,
  113.                                         size);
  114.                 }
  115.         }
  116. #endif  // end of ifdef memstats
  117.  
  118.         if ( num_blocks >= MAX_INDEX )  {
  119.                 con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs." );            
  120.                 con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", var, filename, line );
  121.                 Error( "MEM_OUT_OF_SLOTS" );
  122.         }
  123.  
  124.         id = free_list[ num_blocks++ ];
  125.  
  126.         if (id > LargestIndex ) LargestIndex = id;
  127.  
  128.         if (id==-1)
  129.         {
  130.                 con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs." );            
  131.                 //con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] );
  132.                 Error( "MEM_OUT_OF_SLOTS" );
  133.         }
  134.         ptr = malloc(size + DXX_DEBUG_BIAS_MEMORY_ALLOCATION + CHECKSIZE);
  135.  
  136.         if (ptr==NULL)
  137.         {
  138.                 out_of_memory = 1;
  139.                 con_printf(CON_CRITICAL, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL" );
  140.                 con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] );
  141.                 Error( "MEM_OUT_OF_MEMORY" );
  142.         }
  143.         ptr = reinterpret_cast<char *>(ptr) + DXX_DEBUG_BIAS_MEMORY_ALLOCATION;
  144.         MallocBase[id] = ptr;
  145.         MallocSize[id] = size;
  146.         Varname[id] = var;
  147.         Filename[id] = filename;
  148.         LineNum[id] = line;
  149.         Present[id]    = 1;
  150.  
  151.         pc = reinterpret_cast<char *>(ptr);
  152.  
  153.         BytesMalloced += size;
  154.  
  155.         for (int i=0; i<CHECKSIZE; i++ )
  156.                 pc[size+i] = CHECKBYTE;
  157.  
  158.         return ptr;
  159. }
  160.  
  161. void *(mem_calloc)( size_t nmemb, size_t size, const char * var, const char * filename, unsigned line)
  162. {
  163.         size_t threshold = 1, request = nmemb * size;
  164.         threshold <<= (4 * sizeof(threshold));
  165.         if ((nmemb | size) >= threshold) {
  166.                 /* possible overflow condition */
  167.                 if (request / size != nmemb)
  168.                         request = ~static_cast<size_t>(0);
  169.         }
  170.         void *ptr = mem_malloc(request, var, filename, line);
  171.         if (ptr)
  172.                 memset( ptr, 0, request );
  173.         return ptr;
  174. }
  175.  
  176. static int mem_find_id( void * buffer )
  177. {
  178.         for (int i=0; i<=LargestIndex; i++ )
  179.           if (Present[i]==1)
  180.             if (MallocBase[i] == buffer )
  181.               return i;
  182.  
  183.         // Didn't find id.
  184.         return -1;
  185. }
  186.  
  187. static int mem_check_integrity( int block_number )
  188. {
  189.         int ErrorCount;
  190.         uint8_t * CheckData;
  191.  
  192.         CheckData = reinterpret_cast<uint8_t *>(reinterpret_cast<char *>(MallocBase[block_number]) + MallocSize[block_number]);
  193.  
  194.         ErrorCount = 0;
  195.                        
  196.         for (int i=0; i<CHECKSIZE; i++ )
  197.                 if (CheckData[i] != CHECKBYTE ) {
  198.                         ErrorCount++;
  199.                         con_printf(CON_CRITICAL, "OA: %p ", &CheckData[i] );
  200.                 }
  201.  
  202.         if (ErrorCount &&  (!out_of_memory))    {
  203.                 con_printf(CON_CRITICAL, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten." );
  204.                 PrintInfo( block_number );
  205.                 con_printf(CON_CRITICAL, "\t%d/%d check bytes were overwritten.", ErrorCount, CHECKSIZE );
  206.                 Int3();
  207.         }
  208.  
  209.         return ErrorCount;
  210.  
  211. }
  212.  
  213. void mem_free( void * buffer )
  214. {
  215.         int id;
  216.  
  217.         if (Initialized==0)
  218.                 mem_init();
  219.  
  220. #if MEMSTATS
  221.         {
  222.                 unsigned long   theFreeMem = 0;
  223.        
  224.                 if (sMemStatsFileInitialized)
  225.                 {
  226.                         theFreeMem = FreeMem();
  227.                
  228.                         fprintf(sMemStatsFile,
  229.                                         "\n%9u bytes free before attempting: FREE", theFreeMem);
  230.                 }
  231.         }
  232. #endif  // end of ifdef memstats
  233.  
  234.         if (buffer==NULL  &&  (!out_of_memory))
  235.         {
  236.                 con_printf(CON_CRITICAL, "\nMEM_FREE_NULL: An attempt was made to free the null pointer." );
  237.                 Warning( "MEM: Freeing the NULL pointer!" );
  238.                 Int3();
  239.                 return;
  240.         }
  241.         id = mem_find_id( buffer );
  242.  
  243.         if (id==-1 &&  (!out_of_memory))
  244.         {
  245.                 con_printf(CON_CRITICAL, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included." );
  246.                 Warning( "MEM: Freeing a non-malloced pointer!" );
  247.                 Int3();
  248.                 return;
  249.         }
  250.        
  251.         mem_check_integrity( id );
  252.        
  253.         BytesMalloced -= MallocSize[id];
  254.  
  255.         buffer = reinterpret_cast<char *>(buffer) - DXX_DEBUG_BIAS_MEMORY_ALLOCATION;
  256.         free( buffer );
  257.  
  258.         Present[id] = 0;
  259.         MallocBase[id] = 0;
  260.         MallocSize[id] = 0;
  261.  
  262.         free_list[ --num_blocks ] = id;
  263. }
  264.  
  265. void *mem_realloc(void *buffer, size_t size, const char *var, const char *filename, unsigned line)
  266. {
  267.         void *newbuffer;
  268.         int id;
  269.  
  270.         if (Initialized==0)
  271.                 mem_init();
  272.  
  273.         if (size == 0) {
  274.                 mem_free(buffer);
  275.                 newbuffer = NULL;
  276.         } else if (buffer == NULL) {
  277.                 newbuffer = mem_malloc(size, var, filename, line);
  278.         } else {
  279.                 newbuffer = mem_malloc(size, var, filename, line);
  280.                 if (newbuffer != NULL) {
  281.                         id = mem_find_id(buffer);
  282.                         if (MallocSize[id] < size)
  283.                                 size = MallocSize[id];
  284.                         memcpy(newbuffer, buffer, size);
  285.                         mem_free(buffer);
  286.                 }
  287.         }
  288.         return newbuffer;
  289. }
  290.  
  291. void mem_display_blocks()
  292. {
  293.         int numleft;
  294.  
  295.         if (Initialized==0) return;
  296.        
  297. #if MEMSTATS
  298.         {      
  299.                 if (sMemStatsFileInitialized)
  300.                 {
  301.                         unsigned long   theFreeMem = 0;
  302.  
  303.                         theFreeMem = FreeMem();
  304.                
  305.                         fprintf(sMemStatsFile,
  306.                                         "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
  307.                         fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
  308.                         fclose(sMemStatsFile);
  309.                 }
  310.         }
  311. #endif  // end of ifdef memstats
  312.  
  313.         numleft = 0;
  314.         for (int i=0; i<=LargestIndex; i++ )
  315.         {
  316.                 if (Present[i]==1 &&  (!out_of_memory))
  317.                 {
  318.                         numleft++;
  319.                         if (CGameArg.DbgShowMemInfo)    {
  320.                                 con_printf(CON_CRITICAL, "\nMEM_LEAKAGE: Memory block has not been freed." );
  321.                                 PrintInfo( i );
  322.                         }
  323.                 }
  324.         }
  325.  
  326.         if (numleft &&  (!out_of_memory))
  327.         {
  328.                 Warning( "MEM: %d blocks were left allocated!\n", numleft );
  329.         }
  330.  
  331. }
  332.  
  333. void mem_validate_heap()
  334. {
  335.         for (int i=0; i<LargestIndex; i++  )
  336.                 if (Present[i]==1 )
  337.                         mem_check_integrity( i );
  338. }
  339.  
  340. #else
  341.  
  342. static int Initialized = 0;
  343. static unsigned int SmallestAddress = 0xFFFFFFF;
  344. static unsigned int LargestAddress = 0x0;
  345. static unsigned int BytesMalloced = 0;
  346.  
  347. void mem_init()
  348. {
  349.         Initialized = 1;
  350.  
  351.         SmallestAddress = 0xFFFFFFF;
  352.         LargestAddress = 0x0;
  353.  
  354.         atexit(mem_display_blocks);
  355. }
  356.  
  357. void mem_display_blocks()
  358. {
  359.         if (Initialized==0) return;
  360.  
  361. #if MEMSTATS
  362.         {      
  363.                 if (sMemStatsFileInitialized)
  364.                 {
  365.                         unsigned long   theFreeMem = 0;
  366.  
  367.                         theFreeMem = FreeMem();
  368.                
  369.                         fprintf(sMemStatsFile,
  370.                                         "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
  371.                         fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
  372.                         fclose(sMemStatsFile);
  373.                 }
  374.         }
  375. #endif  // end of ifdef memstats
  376.  
  377.         if (BytesMalloced != 0 )        {
  378.                 con_printf(CON_CRITICAL, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.", BytesMalloced );
  379.         }
  380.  
  381.         if (CGameArg.DbgShowMemInfo)    {
  382.                 con_printf(CON_CRITICAL, "\n\nMEMORY USAGE:" );
  383.                 con_printf(CON_CRITICAL, "  %u Kbytes dynamic data", (LargestAddress-SmallestAddress+512)/1024 );
  384.                 con_printf(CON_CRITICAL, "  %u Kbytes code/static data.", (SmallestAddress-(4*1024*1024)+512)/1024 );
  385.                 con_printf(CON_CRITICAL, "  ---------------------------" );
  386.                 con_printf(CON_CRITICAL, "  %u Kbytes required.",       (LargestAddress-(4*1024*1024)+512)/1024 );
  387.         }
  388. }
  389.  
  390. void mem_validate_heap()
  391. {
  392. }
  393.  
  394. #endif
  395. #endif
  396.  
  397. }
  398.