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.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmMem.h"
  6. #include "cmFloatTypes.h"
  7. #include "cmMath.h"
  8. // Block layout
  9. //
  10. // |a |b |c |d |e |f
  11. // |xx...xxx|yyyy|zzzz|gggggggg|ddd...ddd|gggggggg|
  12. //
  13. //
  14. // xxxx = alignment (prefix) bytes - size is given by yyyy (may contain up to alignByteCnt-1 bytes).
  15. // yyyy = count of bytes preceding yyyy
  16. // zzzz = count of data bytes
  17. // gggg = guard area (size is fixed by guardByteCnt arg. to cmMemInitialize())
  18. // dddd = data area
  19. //
  20. // d = e - guardByteCnt
  21. // c = d - sizeof(unsigned)
  22. // b = c - sizeof(unsigned)
  23. // a = b - yyyy
  24. //
  25. // Notes:
  26. // 1) The smallest allocation is dataByteCnt + (2*sizeof(unsigned)
  27. // 2) If allocByteCnt > 0 then the smallest allocation is allocByteCnt + (2*sizeof(unsigned)) + dataByteCnt.
  28. //
  29. #define _cmMmDataToByteCntPtr( dp, gbc ) (dp==NULL?NULL:(((char*)(dp))-(gbc)-sizeof(unsigned)))
  30. #define _cmMmDataToByteCnt( dp, gbc ) (dp==NULL?0 :(*(unsigned*)_cmMmDataToByteCntPtr(dp,gbc)))
  31. #define _cmMmDataToPrefixCntPtr( dp, gbc ) (dp==NULL?NULL:( _cmMmDataToByteCntPtr(dp,gbc) - sizeof(unsigned)))
  32. #define _cmMmDataToPrefixCnt( dp, gbc ) (dp==NULL?0 :(*(unsigned*)_cmMmDataToPrefixCntPtr(dp,gbc)))
  33. #define _cmMmDataToBasePtr( dp, gbc ) (dp==NULL?NULL:(_cmMmDataToPrefixCntPtr(dp,gbc) - _cmMmDataToPrefixCnt(dp,gbc)))
  34. #define _cmMmDataToTotalByteCnt( dp, gbc ) (dp==NULL?0 :(sizeof(unsigned) + (2*gbc) + _cmMmDataToByteCnt(dp,gbc) + (_cmMmDataToPrefixCnt(dp,gbc) + sizeof(unsigned))))
  35. #define _cmMmDataToPreGuardPtr( dp, gbc ) (dp==NULL?NULL:(((char*)(dp))-(gbc)))
  36. #define _cmMmDataToPostGuardPtr( dp, gbc ) (dp==NULL?NULL:(((char*)(dp))+_cmMmDataToByteCnt(dp,gbc)))
  37. enum
  38. {
  39. kFreedMmFl = 0x01,
  40. kDblFreeMmFl = 0x02
  41. };
  42. typedef struct cmMmRecd_str
  43. {
  44. unsigned uniqueId; //
  45. void* dataPtr; // dataPtr may be NULL if the assoc'd alloc request was for 0 bytes.
  46. unsigned dataByteCnt; // data area bytes on original allocation
  47. unsigned fileLine;
  48. const char* fileNameStr;
  49. const char* funcNameStr;
  50. unsigned flags;
  51. struct cmMmRecd_str* linkPtr;
  52. } cmMmRecd_t;
  53. typedef struct
  54. {
  55. cmRpt_t* rpt;
  56. cmErr_t err;
  57. cmMmRecd_t* listPtr;
  58. unsigned nextId;
  59. unsigned alignByteCnt;
  60. unsigned guardByteCnt;
  61. cmAllocMmFunc_t allocFunc;
  62. cmFreeMmFunc_t freeFunc;
  63. void* funcArgPtr;
  64. char uninitChar;
  65. char freeChar;
  66. char guardChar;
  67. unsigned flags;
  68. } cmMm_t;
  69. cmMmH_t cmMmNullHandle = { NULL };
  70. cmMm_t* _cmMmHandleToPtr( cmMmH_t h )
  71. {
  72. assert(h.h != NULL );
  73. return (cmMm_t*)h.h;
  74. }
  75. cmMmRC_t _cmMmCheckGuards( cmMm_t* p, cmMmRecd_t* rp )
  76. {
  77. // it is possible that dataPtr is NULL if zero bytes was requested at allocation
  78. if( rp->dataPtr == NULL )
  79. return kOkMmRC;
  80. // check the pre data area guard space
  81. char* pp = _cmMmDataToPreGuardPtr( rp->dataPtr, p->guardByteCnt );
  82. char* ep = pp + p->guardByteCnt;
  83. for(;pp<ep; ++pp)
  84. if( *pp != p->guardChar )
  85. return kGuardCorruptMmRC;
  86. // check the post data area guard space
  87. pp = _cmMmDataToPostGuardPtr( rp->dataPtr, p->guardByteCnt );
  88. ep = pp + p->guardByteCnt;
  89. for(;pp<ep; ++pp)
  90. if( *pp != p->guardChar )
  91. return kGuardCorruptMmRC;
  92. // if this block was freed and the kFillFreedMmFl was set then check for write-after-free
  93. if( cmIsFlag(rp->flags,kFreedMmFl) && cmIsFlag(p->flags,kFillFreedMmFl) )
  94. {
  95. pp = rp->dataPtr;
  96. ep = pp + _cmMmDataToByteCnt(pp,p->guardByteCnt);
  97. for(; pp<ep; ++pp)
  98. if( *pp != p->freeChar )
  99. return kWriteAfterFreeMmRC;
  100. }
  101. return kOkMmRC;
  102. }
  103. cmMmRecd_t* _cmMmFindRecd( cmMm_t* p, const void* dataPtr )
  104. {
  105. cmMmRecd_t* rp = p->listPtr;
  106. while( rp != NULL )
  107. {
  108. if( rp->dataPtr == dataPtr )
  109. break;
  110. rp = rp->linkPtr;
  111. }
  112. return rp;
  113. }
  114. cmMmRC_t _cmMmFree( cmMm_t* p, void* dataPtr, cmMmRecd_t* rp )
  115. {
  116. cmMmRC_t rc = kOkMmRC;
  117. if( p->freeFunc(p->funcArgPtr, _cmMmDataToBasePtr(dataPtr,p->guardByteCnt)) == false )
  118. {
  119. if( rp == NULL )
  120. rc = cmErrMsg(&p->err,kFreeFailMmRC,"Memory free failed on data area at %p.",dataPtr);
  121. else
  122. rc = cmErrMsg(&p->err,kFreeFailMmRC,"Memory free failed on data area at %p. Allocated with id:%i at %s line:%i %s.",dataPtr, rp->uniqueId,rp->funcNameStr,rp->fileLine,rp->fileNameStr);
  123. }
  124. return rc;
  125. }
  126. cmMmRC_t _cmMmFreeP( cmMm_t* p, void* dataPtr )
  127. {
  128. if( dataPtr == NULL )
  129. return kOkMmRC;
  130. cmMmRecd_t* rp = p->listPtr;
  131. cmMmRC_t rc = kOkMmRC;
  132. // if we are tracking alloc's and free's
  133. if( cmIsFlag(p->flags,kTrackMmFl) )
  134. {
  135. // locate the tracking recd
  136. rp = _cmMmFindRecd(p,dataPtr);
  137. // if no tracking recd was found
  138. if( rp == NULL )
  139. return cmErrMsg(&p->err,kMissingRecdMmRC,"Unable to locate a tracking record associated with released data area pointer:%p.",dataPtr);
  140. // if this block was already freed then this is a double free
  141. if( cmIsFlag(rp->flags,kFreedMmFl) )
  142. rp->flags = cmSetFlag(rp->flags,kDblFreeMmFl);
  143. else
  144. // otherwise fill the freed block with the freeChar (if requested)
  145. if( cmIsFlag(p->flags,kFillFreedMmFl) )
  146. memset(dataPtr, p->freeChar, _cmMmDataToByteCnt(dataPtr,p->guardByteCnt));
  147. // mark the block as having been freed
  148. rp->flags = cmSetFlag(rp->flags,kFreedMmFl);
  149. }
  150. // if we are not deferring free to the finalize stage ... then free the memory here
  151. if( cmIsFlag(p->flags,kDeferFreeMmFl) == false)
  152. rc = _cmMmFree(p,dataPtr,rp);
  153. return rc;
  154. }
  155. void* _cmMmAllocate(cmMm_t* p, void* orgDataPtr, unsigned newByteCnt, unsigned flags )
  156. {
  157. unsigned abc = cmIsFlag(flags,kAlignMmFl) ? p->alignByteCnt : 0;
  158. unsigned gbc = p->guardByteCnt;
  159. char* bp = NULL;
  160. char* dp = NULL;
  161. char* idp = NULL;
  162. unsigned orgByteCnt = 0;
  163. unsigned prefixByteCnt = 0;
  164. // Determine the total allocation block size including the auxillary data.
  165. //
  166. // alignment bytes + data_byte_cnt + guard bytes + actual data
  167. unsigned ttlByteCnt = abc+sizeof(unsigned) + sizeof(unsigned) + (2*gbc) + newByteCnt;
  168. // if this is a reallocation
  169. if( orgDataPtr != NULL )
  170. {
  171. // asking to reallocate a block with zero bytes free's the original block and returns NULL
  172. // (this is in keeping with realloc() behaviour)
  173. if( newByteCnt == 0 )
  174. {
  175. _cmMmFreeP(p,orgDataPtr);
  176. return NULL;
  177. }
  178. // get the size of the currently allocated block
  179. orgByteCnt = _cmMmDataToByteCnt(orgDataPtr,gbc);
  180. // if the requested data area is <= the alloc'd data area
  181. if( newByteCnt <= orgByteCnt)
  182. {
  183. // if preservation was requested simply return with the original data area ptr
  184. if( cmIsFlag(flags,kPreserveMmFl) )
  185. return orgDataPtr;
  186. // otherwise initialze the data area
  187. dp = orgDataPtr;
  188. goto initLabel;
  189. }
  190. // expansion was requested
  191. }
  192. // if an empty data area was requested
  193. if( newByteCnt == 0 )
  194. return NULL;
  195. //
  196. // A new data block must be allocated
  197. //
  198. // allocate the memory block via a callback
  199. if((bp = p->allocFunc(p->funcArgPtr,ttlByteCnt)) == NULL )
  200. {
  201. cmErrMsg(&p->err,kAllocFailMmRC,"Attempt to allocate %i bytes failed.",ttlByteCnt);
  202. goto errLabel;
  203. }
  204. // make the data area offset: data_byte_cnt + guard bytes
  205. dp = bp + (2*sizeof(unsigned)) + gbc;
  206. if( abc )
  207. {
  208. unsigned long alignMask = abc - 1;
  209. // alignment requires an additional offset
  210. dp += abc;
  211. // align the data area to the specified boundary
  212. char* ndp = ((char*)((unsigned long)dp & (~alignMask)));
  213. prefixByteCnt = abc - (dp - ndp);
  214. dp = ndp;
  215. }
  216. // set the prefix byteCnt
  217. *(unsigned*)_cmMmDataToPrefixCntPtr(dp,gbc) = prefixByteCnt;
  218. // set the data area byte cnt
  219. *(unsigned*)_cmMmDataToByteCntPtr(dp,gbc) = newByteCnt;
  220. // uncomment this line to print memory layout information for each block
  221. //printf("prefix:%i prefix*:%p bytes:%i bytes*:%p base:%p==%p data:%p\n",_cmMmDataToPrefixCnt(dp,gbc),_cmMmDataToPrefixCntPtr(dp,gbc),_cmMmDataToByteCnt(dp,gbc),_cmMmDataToByteCntPtr(dp,gbc),_cmMmDataToBasePtr(dp,gbc),bp,dp);
  222. // set the guard bytes
  223. if( gbc )
  224. {
  225. void* gp = _cmMmDataToPreGuardPtr( dp,gbc);
  226. if( gp != NULL )
  227. memset(gp, p->guardChar, gbc);
  228. gp = _cmMmDataToPostGuardPtr( dp,gbc);
  229. if( gp != NULL )
  230. memset(gp, p->guardChar, gbc);
  231. }
  232. initLabel:
  233. //
  234. // initialize the new data area
  235. //
  236. idp = dp;
  237. // if this is a reallocation with expansion ...
  238. if( orgDataPtr != NULL && newByteCnt > orgByteCnt )
  239. {
  240. // ... and preservation was requested
  241. if( cmIsFlag(flags,kPreserveMmFl) )
  242. {
  243. // copy original data into the new block
  244. memcpy(idp,orgDataPtr,orgByteCnt);
  245. idp += orgByteCnt;
  246. newByteCnt -= orgByteCnt;
  247. }
  248. _cmMmFreeP(p,orgDataPtr); // free the original data block
  249. }
  250. // if zeroing was requested
  251. if( cmIsFlag(flags,kZeroMmFl))
  252. memset(idp,0,newByteCnt);
  253. else
  254. // if uninitialized data should be set to a known character
  255. if( cmIsFlag(p->flags,kFillUninitMmFl) )
  256. memset(idp,p->uninitChar,newByteCnt);
  257. return dp;
  258. errLabel:
  259. return NULL;
  260. }
  261. cmMmRC_t cmMmInitialize(
  262. cmMmH_t* hp,
  263. cmAllocMmFunc_t allocFunc,
  264. cmFreeMmFunc_t freeFunc,
  265. void* funcArgPtr,
  266. unsigned guardByteCnt,
  267. unsigned alignByteCnt,
  268. unsigned flags,
  269. cmRpt_t* rpt )
  270. {
  271. cmMm_t* p;
  272. cmErr_t err;
  273. cmErrSetup(&err,rpt,"Memory Manager");
  274. // validate alignByteCnt
  275. if(alignByteCnt>0 && cmIsPowerOfTwo(alignByteCnt)==false)
  276. return cmErrMsg(&err,kParamErrMmRC,"The 'alignByteCnt' parameter must be a power of two.");
  277. // allocate the main object
  278. if((p= calloc(1,sizeof(cmMm_t))) == NULL )
  279. return cmErrMsg(&err,kObjAllocFailMmRC,"Object allocation failed.");
  280. // setting kDeferFreeMmFl only makes sense when kTrackMmFl is also set
  281. if(cmIsFlag(flags,kTrackMmFl)==false && cmIsFlag(flags,kDeferFreeMmFl)==true)
  282. {
  283. cmErrMsg(&err,kParamErrMmRC,"The flag 'kDeferFreeMmFl' may only be set if the 'kTrackMmFl' is also set. 'kDeferFreeMmFl' is begin disabled.");
  284. flags = cmClrFlag(flags,kDeferFreeMmFl);
  285. }
  286. cmErrClone(&p->err,&err);
  287. p->rpt = rpt;
  288. p->alignByteCnt = alignByteCnt;
  289. p->guardByteCnt = guardByteCnt;
  290. p->allocFunc = allocFunc;
  291. p->freeFunc = freeFunc;
  292. p->funcArgPtr = funcArgPtr;
  293. p->uninitChar = 0x55; // non-zeroed data areas are automatically filled w/ this value on allocation
  294. p->freeChar = 0x33; // data areas are overwritten with this value on free
  295. p->guardChar = 0xAA; // guard areas are set with this value
  296. p->flags = flags;
  297. hp->h = p;
  298. return kOkMmRC;
  299. }
  300. cmMmRC_t cmMmFinalize( cmMmH_t* hp )
  301. {
  302. cmMm_t* p;
  303. cmMmRC_t rc = kOkMmRC;
  304. if( hp == NULL || cmMmIsValid(*hp)==false )
  305. return kOkMmRC;
  306. p = _cmMmHandleToPtr(*hp);
  307. cmMmRecd_t* rp = p->listPtr;
  308. while( rp != NULL )
  309. {
  310. cmMmRecd_t* tp = rp->linkPtr;
  311. cmMmRC_t rrc;
  312. if( cmIsFlag(p->flags,kDeferFreeMmFl) )
  313. if((rrc = _cmMmFree(p,rp->dataPtr,rp)) != kOkMmRC )
  314. rc = rrc;
  315. free(rp);
  316. rp = tp;
  317. }
  318. free(p);
  319. hp->h = NULL;
  320. return rc;
  321. }
  322. unsigned cmMmGuardByteCount( cmMmH_t h )
  323. {
  324. cmMm_t* p = _cmMmHandleToPtr(h);
  325. return p->guardByteCnt;
  326. }
  327. unsigned cmMmAlignByteCount( cmMmH_t h )
  328. {
  329. cmMm_t* p = _cmMmHandleToPtr(h);
  330. return p->alignByteCnt;
  331. }
  332. unsigned cmMmInitializeFlags( cmMmH_t h )
  333. {
  334. cmMm_t* p = _cmMmHandleToPtr(h);
  335. return p->flags;
  336. }
  337. bool cmMmIsValid( cmMmH_t h )
  338. { return h.h != NULL; }
  339. void* cmMmAllocate(
  340. cmMmH_t h,
  341. void* orgDataPtr,
  342. unsigned newEleCnt,
  343. unsigned newEleByteCnt,
  344. enum cmMmAllocFlags_t flags,
  345. const char* fileName,
  346. const char* funcName,
  347. unsigned fileLine )
  348. {
  349. cmMm_t* p = _cmMmHandleToPtr(h);
  350. unsigned newByteCnt = newEleCnt * newEleByteCnt;
  351. void* ndp = _cmMmAllocate(p,orgDataPtr,newByteCnt,flags);
  352. /*
  353. if( p->nextId == 1575 )
  354. {
  355. cmErrMsg(&p->err,kOkMmRC,"Breakpoint for memory allocation id:%i.",p->nextId);
  356. }
  357. */
  358. // if we are tracking changes
  359. if( cmIsFlag(p->flags,kTrackMmFl) )
  360. {
  361. //
  362. // NOTE: it is possible that ndp is NULL if newByteCnt == 0.
  363. //
  364. cmMmRecd_t* rp = NULL;
  365. // if a new memory block was allocated
  366. if( orgDataPtr == NULL || orgDataPtr != ndp )
  367. {
  368. // allocate a new tracking recd
  369. if( (rp = calloc(1,sizeof(cmMmRecd_t))) == NULL )
  370. {
  371. cmErrMsg(&p->err,kTrkAllocFailMmRC,"Unable to allocate a tracking record for %s line:%i %s.",funcName,fileLine,fileName);
  372. return ndp;
  373. }
  374. // initialize the new tracking recd
  375. rp->uniqueId = p->nextId;
  376. rp->dataPtr = ndp;
  377. rp->dataByteCnt = newByteCnt;
  378. rp->fileLine = fileLine;
  379. rp->fileNameStr = fileName;
  380. rp->funcNameStr = funcName;
  381. rp->flags = 0;
  382. rp->linkPtr = p->listPtr;
  383. //printf("%i %i %s %i %s\n",rp->uniqueId,newByteCnt,funcName,fileLine,fileName);
  384. p->listPtr = rp;
  385. assert( _cmMmCheckGuards(p,rp) == kOkMmRC );
  386. ++p->nextId;
  387. }
  388. else // a reallocation occurred.
  389. if( orgDataPtr == ndp )
  390. {
  391. if((rp = _cmMmFindRecd(p,orgDataPtr)) == NULL )
  392. cmErrMsg(&p->err,kMissingRecdMmRC,"Unable to locate a tracking record associated with reallocation data area pointer:%p.",orgDataPtr);
  393. }
  394. }
  395. return ndp;
  396. }
  397. cmMmRC_t cmMmFree( cmMmH_t h, void* dataPtr )
  398. {
  399. cmMm_t* p = _cmMmHandleToPtr(h);
  400. return _cmMmFreeP(p,dataPtr);
  401. }
  402. cmMmRC_t cmMmFreeDebug( cmMmH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine )
  403. {
  404. cmMmRC_t rc;
  405. if((rc = cmMmFree(h,dataPtr)) != kOkMmRC )
  406. cmErrMsg(&_cmMmHandleToPtr(h)->err,rc,"Memory free failed at %s() line:%i %s",funcName,fileLine,fileName);
  407. return rc;
  408. }
  409. cmMmRC_t cmMmFreePtr( cmMmH_t h, void** dataPtrPtr )
  410. {
  411. assert(dataPtrPtr != NULL );
  412. cmMmRC_t rc = cmMmFree(h,*dataPtrPtr);
  413. *dataPtrPtr = NULL;
  414. return rc;
  415. }
  416. cmMmRC_t cmMmFreePtrDebug( cmMmH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine )
  417. {
  418. cmMmRC_t rc;
  419. if((rc = cmMmFreePtr(h,dataPtr)) != kOkMmRC )
  420. cmErrMsg(&_cmMmHandleToPtr(h)->err,rc,"Memory free failed at %s() line:%i %s",funcName,fileLine,fileName);
  421. return rc;
  422. }
  423. unsigned cmMmByteCount( cmMmH_t h, const void* dataPtr )
  424. {
  425. cmMm_t* p = _cmMmHandleToPtr(h);
  426. return _cmMmDataToByteCnt(dataPtr,p->guardByteCnt);
  427. }
  428. unsigned cmMmDebugId( cmMmH_t h, const void* dataPtr)
  429. {
  430. cmMm_t* p = _cmMmHandleToPtr(h);
  431. const cmMmRecd_t* rp = NULL;
  432. // if we are tracking alloc's and free's
  433. if( cmIsFlag(p->flags,kTrackMmFl) )
  434. {
  435. // locate the tracking recd
  436. rp = _cmMmFindRecd(p,dataPtr);
  437. }
  438. return rp==NULL ? cmInvalidId : rp->uniqueId;
  439. }
  440. cmMmRC_t _cmMmError( cmMm_t* p, cmMmRC_t rc, const cmMmRecd_t* rp, const char* msg )
  441. {
  442. return cmErrMsg(&p->err,rc,"%s detected on block id:%i from %s() line:%i %s.",msg,rp->uniqueId,rp->funcNameStr,rp->fileLine,rp->fileNameStr);
  443. }
  444. cmMmRC_t _cmMmRecdPrint( cmMm_t* p, cmMmRecd_t* rp, cmMmRC_t rc )
  445. {
  446. void* dp = rp->dataPtr;
  447. unsigned gbc = p->guardByteCnt;
  448. char* lbl = NULL;
  449. switch( rc )
  450. {
  451. case kOkMmRC: lbl = "Ok "; break;
  452. case kLeakDetectedMmRC: lbl = "Memory Leak "; break;
  453. case kWriteAfterFreeMmRC: lbl = "Write After Free"; break;
  454. case kDblFreeDetectedMmRC: lbl = "Double Free "; break;
  455. case kGuardCorruptMmRC: lbl = "Guard Corrupt "; break;
  456. default:
  457. lbl = "Unknown Status ";
  458. }
  459. cmRptPrintf(p->err.rpt,"%s id:%5i data:%p : data:%5i prefix:%5i total:%5i base:%p : %5i %s %s\n",
  460. lbl,rp->uniqueId,rp->dataPtr,
  461. _cmMmDataToByteCnt(dp,gbc),
  462. _cmMmDataToPrefixCnt(dp,gbc),
  463. _cmMmDataToTotalByteCnt(dp,gbc),
  464. _cmMmDataToBasePtr(dp,gbc),
  465. rp->fileLine,rp->funcNameStr,rp->fileNameStr );
  466. return rc;
  467. }
  468. cmMmRC_t cmMmReport( cmMmH_t h, unsigned flags )
  469. {
  470. cmMm_t* p = _cmMmHandleToPtr(h);
  471. unsigned allocByteCnt = 0;
  472. unsigned ttlByteCnt = 0;
  473. unsigned dataFrByteCnt = 0;
  474. unsigned ttlFrByteCnt = 0;
  475. unsigned dataLkByteCnt = 0;
  476. unsigned ttlLkByteCnt = 0;
  477. unsigned allocBlkCnt = 0;
  478. unsigned freeBlkCnt = 0;
  479. unsigned leakBlkCnt = 0;
  480. cmMmRecd_t* rp = p->listPtr;
  481. cmMmRC_t ret_rc = kOkMmRC;
  482. for(; rp != NULL; rp = rp->linkPtr,++allocBlkCnt )
  483. {
  484. cmMmRC_t rc = kOkMmRC;
  485. unsigned blkDataByteCnt = _cmMmDataToByteCnt(rp->dataPtr,p->guardByteCnt);
  486. unsigned blkTtlByteCnt = _cmMmDataToTotalByteCnt(rp->dataPtr,p->guardByteCnt);
  487. allocByteCnt += blkDataByteCnt;
  488. ttlByteCnt += blkTtlByteCnt;
  489. // if this block was freed or never alloc'd
  490. if( cmIsFlag(rp->flags,kFreedMmFl) || rp->dataPtr == NULL )
  491. {
  492. ++freeBlkCnt;
  493. dataFrByteCnt += blkDataByteCnt;
  494. ttlFrByteCnt += blkTtlByteCnt;
  495. }
  496. else // if this block leaked
  497. {
  498. ++leakBlkCnt;
  499. dataLkByteCnt += blkDataByteCnt;
  500. ttlLkByteCnt += blkTtlByteCnt;
  501. if( cmIsFlag(flags,kIgnoreLeaksMmFl) == false )
  502. rc = _cmMmRecdPrint(p,rp,kLeakDetectedMmRC);
  503. }
  504. // if this block was double freed
  505. if( cmIsFlag(rp->flags,kDblFreeMmFl) )
  506. rc = _cmMmRecdPrint(p,rp,kDblFreeDetectedMmRC);
  507. // check for guard corruption and write-after-free
  508. cmMmRC_t t_rc = _cmMmCheckGuards(p,rp);
  509. switch( t_rc )
  510. {
  511. case kOkMmRC:
  512. break;
  513. case kGuardCorruptMmRC:
  514. rc = _cmMmRecdPrint(p,rp,t_rc);
  515. break;
  516. case kWriteAfterFreeMmRC:
  517. rc = _cmMmRecdPrint(p,rp,t_rc);
  518. break;
  519. default:
  520. assert(0);
  521. break;
  522. }
  523. if( rc != kOkMmRC )
  524. ret_rc = rc;
  525. else
  526. {
  527. if( cmIsFlag(flags,kIgnoreNormalMmFl)==false )
  528. _cmMmRecdPrint(p,rp,rc);
  529. }
  530. }
  531. if( p->listPtr != NULL && cmIsFlag(flags,kSuppressSummaryMmFl)==false )
  532. {
  533. cmRptPrintf(p->err.rpt,"Blocks Allocated:%i Freed:%i Leaked:%i\n",allocBlkCnt,freeBlkCnt,leakBlkCnt);
  534. cmRptPrintf(p->err.rpt,"Bytes Allocated: data=%i total=%i Freed: data=%i total=%i Leaked: data=%i total=%i\n",allocByteCnt,ttlByteCnt,dataFrByteCnt,ttlFrByteCnt,dataLkByteCnt,ttlLkByteCnt);
  535. }
  536. return ret_rc;
  537. }
  538. cmMmRC_t cmMmIsGuardCorrupt( cmMmH_t h, unsigned id )
  539. {
  540. cmMm_t* p = _cmMmHandleToPtr(h);
  541. cmMmRecd_t* rp = p->listPtr;
  542. while(rp != NULL )
  543. {
  544. if( rp->uniqueId == id )
  545. break;
  546. rp = rp->linkPtr;
  547. }
  548. if( rp == NULL )
  549. return cmErrMsg(&p->err,kMissingRecdMmRC,"Unable to locate the tracking record associated with id %i.",id);
  550. return _cmMmCheckGuards(p,rp);
  551. }
  552. cmMmRC_t cmMmCheckAllGuards( cmMmH_t h )
  553. {
  554. cmMm_t* p = _cmMmHandleToPtr(h);
  555. cmMmRecd_t* rp = p->listPtr;
  556. cmMmRC_t rc = kOkMmRC;
  557. while(rp != NULL )
  558. {
  559. if((rc = _cmMmCheckGuards(p,rp)) != kOkMmRC )
  560. rc = cmErrMsg(&p->err,rc,"A corrupt guard or 'write after free' was detected in the data area allocated with id:%i at %s (line:%i) %s.",rp->uniqueId,rp->funcNameStr,rp->fileLine,rp->fileNameStr);
  561. rp = rp->linkPtr;
  562. }
  563. return rc;
  564. }