libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmMem.h 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. //( { file_desc: "Implements a memory allocation manager interface." kw:[ base ]}
  4. //
  5. //
  6. // Using cmMem allows memory leaks and some instances of memory corruption
  7. // to be be detected. It can also perform memory block alignment.
  8. //
  9. // The cmMm class acts as an interface for implementing functions designed to replace
  10. // malloc() and free(). cmMm does not actually allocate memory itself but rather
  11. // tracks and conditions block of memory provided by other sources. In this sense
  12. // it acts as a backend for a memory allocation manager.
  13. // cmMallocDebug.h gives an example of using cmMm to interface to malloc() and free().
  14. // cmLinkedHeap.h gives an example of using cmMm to link to an alternate heap manager.
  15. // See cmMdTest() and cmLHeapTest() for usage examples of cmMm.
  16. //
  17. // cmMm works as follows:
  18. //
  19. // 1. A client memory manager creates and configures a cmMm object via cmMmInitialize().
  20. // As part of the configuration the client gives callback functions which implement
  21. // actual memory allocation and release. In practice this means the callback probably
  22. // call malloc() or free().
  23. //
  24. // 2. At some point later when the client needs to allocate a block of memory it calls
  25. // cmMmAllocate() with the size of the requested block. cmMm translates this request
  26. // into a call to the client provided memory allocation callback to get a block of raw
  27. // memory which is slightly larger than the request block.
  28. //
  29. // 3. Given the raw memory block cmMm conditions it in the following ways and returns
  30. // it to the client.
  31. //
  32. // * The base of the blocks data area is shifted such that it is has an arbitrary
  33. // address aligned according to the value set by the alignByteCnt parameter to cmMmInitialize().
  34. // Address aligment is sometimes required by routines which make use of the the SIMD
  35. // unit on some CPUs.
  36. // * 'Guard' bytes are prepended and appended to the blocks data area.
  37. // These bytes are set to the known fixed value (0xaa). At some point later cmMm can
  38. // then test for accidental writes just before or just after the legal data area by
  39. // checking the value of these guard bytes.
  40. // * The number of bytes allocated is written just prior to the leading guard bytes.
  41. // This allows the memory manager to track the
  42. // size of the memory and thereby makes reallocations() to smaller or equal data areas
  43. // very fast. This also allows the size of the data area to be known just by having a
  44. // pointer to the data area (see cmMmByteCount()). This basic information is not availabe
  45. // via malloc().
  46. // * A record is added to an internal database to track the allocation code location
  47. // (file name, file line, function name) and the allocation status (active or released).
  48. // * The client may request that a new block of memory be automatically filled with zeros.
  49. // If automatic zeroing is not requested then the block is filled with 0x55 to indicate that
  50. // it is not initialized. This can be useful when attempting to recognize uninitialized
  51. // memory during debugging.
  52. //
  53. // When a client requests that a block of memory is released cmMm does the following:
  54. //
  55. // 1. If deferred release is enabled (kDeferFreeFl) then the block is filled with 0x33
  56. // but the callback to freeFunc() is not actually made. This allows cmMm to track attempted
  57. // writes to freed memory areas. When deferred release is enabled the freeFunc() is not called
  58. // on any blocks until cmMmFinalize(). If the program continually allocates memory over the
  59. // life of the program this may mean that the program will eventually exhaust physical memory.
  60. //
  61. // 2. If tracking is enabled (kTrackMmFl) then the block pointer is looked up in the internal database.
  62. // If the pointer is not found then a kMissingRecdRC is returned indicating an attempt to release
  63. // a non-allocated block.
  64. //
  65. // 3. If tracking is enabled (kTrackMmFl) then the block is marked as released in the
  66. // internal tracking database. At the end of the program all blocks should be marked for release
  67. // otherwise they are considered leaks.
  68. //
  69. //
  70. // At any time during the life of the cmMm object the client can request a report of the
  71. // allocated blocks cmMmReport(). This report examines each allocated block for corrupt guard bytes,
  72. // double frees (attempts to release an allocated block that was already released), and
  73. // leaked blocks (active blocks).
  74. //
  75. //)
  76. #ifndef cmMem_h
  77. #define cmMem_h
  78. #ifdef __cplusplus
  79. extern "C" {
  80. #endif
  81. //(
  82. typedef cmHandle_t cmMmH_t; //< cmMm handle type.
  83. typedef cmRC_t cmMmRC_t; //< cmMm result code types.
  84. // cmMm result codes
  85. enum
  86. {
  87. kOkMmRC = cmOkRC,
  88. kObjAllocFailMmRC,
  89. kTrkAllocFailMmRC,
  90. kAllocFailMmRC,
  91. kFreeFailMmRC,
  92. kMissingRecdMmRC,
  93. kGuardCorruptMmRC,
  94. kWriteAfterFreeMmRC,
  95. kLeakDetectedMmRC,
  96. kDblFreeDetectedMmRC,
  97. kParamErrMmRC
  98. };
  99. // All cmMmH_t variables should be initialized with this value prior to calling cmMmInitialize().
  100. extern cmMmH_t cmMmNullHandle;
  101. // Function signature for data allocation routine client provided to cmMmInitialize().
  102. // Return NULL if byteCnt == 0.
  103. typedef void* (*cmAllocMmFunc_t)(void* funcArgPtr, unsigned byteCnt);
  104. // Function signature for data release routine client provided to cmMmInitialize().
  105. // Return true on success and false on failure. Return true if ptr==NULL.
  106. typedef bool (*cmFreeMmFunc_t)( void* funcArgPtr, void* ptr);
  107. // Flags for use with cmMmInitialize()
  108. enum
  109. {
  110. kTrackMmFl = 0x01, //< Track alloc's and free's for use by cmMmReport().
  111. kDeferFreeMmFl = 0x02, //< Defer memory release until cmMmFinalize() (ignored unless kTrackMmFl is set.) Allows checks for 'write after release'.
  112. kFillUninitMmFl = 0x04, //< Fill uninitialized (non-zeroed) memory with a 0x55 upon allocation
  113. kFillFreedMmFl = 0x08 //< Fill freed memory with 0x33. This allow checks for wite-after-free.
  114. };
  115. // Create a new cmMm object.
  116. // If *hp was not initalized by an earlier call to cmMmInitialize() then it should
  117. // be set to cmMmNullHandle prior to calling this function. If *hp is a valid handle
  118. // then it is automatically finalized by an internal call to cmMmFinalize() prior to
  119. // being re-iniitalized.
  120. cmMmRC_t cmMmInitialize(
  121. cmMmH_t* hp, //< Pointer to a client provided cmMmH_t handle to recieve the handle of the new object.
  122. cmAllocMmFunc_t allocFunc, //< The memory allocation function equivalent to malloc().
  123. cmFreeMmFunc_t freeFunc, //< The memory release function equivalent to free().
  124. void* funcArgPtr, //< An application supplied data value sent with call backs to allocFunc() and freeFunc().
  125. unsigned guardByteCnt, //< Count of guardBytes to precede and follow each allocated block.
  126. unsigned alignByteCnt, //< Address alignment to provide for each allocated block.
  127. unsigned flags, //< Configuration flags (See cmXXXMmFl).
  128. cmRpt_t* rptPtr //< Pointer to an error reporting object.
  129. );
  130. // Release a cmMm object created by an earlier call to cmMmInitialize(). Upon successful completion *hp is set to cmMmNullHandle.
  131. cmMmRC_t cmMmFinalize( cmMmH_t* hp );
  132. unsigned cmMmGuardByteCount( cmMmH_t h ); //< Return the count of guard bytes this cmMm object is applying.
  133. unsigned cmMmAlignByteCount( cmMmH_t h ); //< Return the byte alignment this cmMm object is applying.
  134. unsigned cmMmInitializeFlags( cmMmH_t h ); //< Return the configuration flags this cmMm object was initialized with.
  135. // Return true if 'h' is a valid handle for an existing cmMm object.
  136. bool cmMmIsValid( cmMmH_t h );
  137. // flags for use with cmMmAllocate()
  138. enum cmMmAllocFlags_t
  139. {
  140. kZeroMmFl = 0x01, //< Initialize new memory area to zero.
  141. kAlignMmFl = 0x02, //< Align the returned memory according to the alignByteCnt set in cmMmInitialize().
  142. kPreserveMmFl = 0x04 //< Preserve existing memory contents during reallocation (orgDataPtr!=NULL).
  143. };
  144. // Allocate a block of memory.
  145. // Calling this function results in a call to the function named in allocFunc() in cmMmInitialize().
  146. void* cmMmAllocate(
  147. cmMmH_t h, //< Handle for this cmMm object returned from an earlier successful call to cmMmInitialize().
  148. void* orgDataPtr, //< If this is a re-allocation then this pointer should point to the original allocation otherwise it should be NULL.
  149. unsigned newEleCnt, //< Count of elmements in this allocation.
  150. unsigned newEleByteCnt, //< Bytes per element in this allocation. The total memory request is newEleCnt*newEleByteCnt.
  151. enum cmMmAllocFlags_t flags, //< See cmMmAllocFlags_t.
  152. const char* fileName, //< Name of the C file from which the allocation request is being made.
  153. const char* funcName, //< Name of the C function from which the allocation request is being made.
  154. unsigned fileLine //< Line in the C file on which the allocation request is being made.
  155. );
  156. // Free memory pointed to by dataPtr.
  157. // If dataPtr==NULL then the functon does nothing and returns.
  158. // Calling this function results in a call to the function named in freeFunc() in cmMmInitialize().
  159. // This is the release mode memory free routine. See cmMmFreeDebug() for the debug mode memory release routine.
  160. // See \ref debug_mode for more about debug vs. release mode.
  161. cmMmRC_t cmMmFree( cmMmH_t h, void* dataPtr );
  162. // Debug mode version of cmMmFree(). See cmMmFree() for the release mode memory free routine.
  163. // See debug_mode for more about debug vs. release mode.
  164. // This routine is functionally identical to the cmMmFree() but takes the calling
  165. // location information for use in tracking the block of memory.
  166. cmMmRC_t cmMmFreeDebug( cmMmH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine );
  167. // This function is identical to cmMmFree() but takes the address of the pointer
  168. // to the block of memory to free. Upon successful completion *dataPtrPtr is
  169. // set to NULL. In general this should be the preferred version of the free routine
  170. // because it helps to eliminate problems of reusing deallocated memory blocks.
  171. // Note that although dataPtrPtr must point to a valid address *dataPtrPtr may be NULL.
  172. // This routine is generally only used in the release compile mode.
  173. // See cmMmFreePtrDebug() for the debug mode version. See \ref debug_mode for more
  174. // about compile vs. release mode.
  175. cmMmRC_t cmMmFreePtr( cmMmH_t h, void** dataPtrPtr );
  176. // Debug compile mode version of cmMmFreePtr().
  177. // This function is functionally identical to cmMmFreePtr() but accepts information
  178. // on the location of the call to aid in debuging.
  179. cmMmRC_t cmMmFreePtrDebug( cmMmH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine );
  180. // Return the size of a memory block returned from cmMmAllocate().
  181. unsigned cmMmByteCount( cmMmH_t h, const void* dataPtr );
  182. // Return the unique id associated with an address returned from cmMmAllocate().
  183. unsigned cmMmDebugId( cmMmH_t h, const void* dataPtr);
  184. // Flags for use with cmMmReport().
  185. enum
  186. {
  187. kSuppressSummaryMmFl = 0x01, //< Do not print a memory use summary report.
  188. kIgnoreNormalMmFl = 0x02, //< Do not print information for non-leaked,non-corrupt memory blocks.
  189. kIgnoreLeaksMmFl = 0x04 //< Do not print information for leaked blocks.
  190. };
  191. // Report on the memory tracking data.
  192. // Returns kMmOkRC if no errors were found otherwise returns the error of the
  193. // last anomoly reported.
  194. cmMmRC_t cmMmReport( cmMmH_t h, unsigned flags );
  195. // Analyze the memory assoc'd with a specific tracking record for corruption.
  196. // Returns: kOkMmRC,kGuardCorruptMmRC,kWriteAfterFreeMmRc, or kMissingRecdMmRC.
  197. // This function is only useful if kTrackMmFl was set in cmMmInitialize().
  198. // Write-after-free errors are only detectable if kDeferFreeMmFl was set in cmMmInitialize().
  199. cmMmRC_t cmMmIsGuardCorrupt( cmMmH_t h, unsigned id );
  200. // Check all tracking records by calling cmMmmIsGuardCorrupt() on each record.
  201. cmMmRC_t cmMmCheckAllGuards( cmMmH_t h );
  202. //)
  203. #ifdef __cplusplus
  204. }
  205. #endif
  206. #endif