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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  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. /*
  141. if( rp->uniqueId == 176690 )
  142. {
  143. cmErrMsg(&p->err,kOkMmRC,"Breakpoint for memory free id:%i.",rp->uniqueId);
  144. }
  145. */
  146. // if this block was already freed then this is a double free
  147. if( cmIsFlag(rp->flags,kFreedMmFl) )
  148. rp->flags = cmSetFlag(rp->flags,kDblFreeMmFl);
  149. else
  150. // otherwise fill the freed block with the freeChar (if requested)
  151. if( cmIsFlag(p->flags,kFillFreedMmFl) )
  152. memset(dataPtr, p->freeChar, _cmMmDataToByteCnt(dataPtr,p->guardByteCnt));
  153. // mark the block as having been freed
  154. rp->flags = cmSetFlag(rp->flags,kFreedMmFl);
  155. }
  156. // if we are not deferring free to the finalize stage ... then free the memory here
  157. if( cmIsFlag(p->flags,kDeferFreeMmFl) == false)
  158. rc = _cmMmFree(p,dataPtr,rp);
  159. return rc;
  160. }
  161. void* _cmMmAllocate(cmMm_t* p, void* orgDataPtr, unsigned newByteCnt, unsigned flags )
  162. {
  163. unsigned abc = cmIsFlag(flags,kAlignMmFl) ? p->alignByteCnt : 0;
  164. unsigned gbc = p->guardByteCnt;
  165. char* bp = NULL;
  166. char* dp = NULL;
  167. char* idp = NULL;
  168. unsigned orgByteCnt = 0;
  169. unsigned prefixByteCnt = 0;
  170. // Determine the total allocation block size including the auxillary data.
  171. //
  172. // alignment bytes + data_byte_cnt + guard bytes + actual data
  173. unsigned ttlByteCnt = abc+sizeof(unsigned) + sizeof(unsigned) + (2*gbc) + newByteCnt;
  174. // if this is a reallocation
  175. if( orgDataPtr != NULL )
  176. {
  177. // asking to reallocate a block with zero bytes free's the original block and returns NULL
  178. // (this is in keeping with realloc() behaviour)
  179. if( newByteCnt == 0 )
  180. {
  181. _cmMmFreeP(p,orgDataPtr);
  182. return NULL;
  183. }
  184. // get the size of the currently allocated block
  185. orgByteCnt = _cmMmDataToByteCnt(orgDataPtr,gbc);
  186. // if the requested data area is <= the alloc'd data area
  187. if( newByteCnt <= orgByteCnt)
  188. {
  189. // if preservation was requested simply return with the original data area ptr
  190. if( cmIsFlag(flags,kPreserveMmFl) )
  191. return orgDataPtr;
  192. // otherwise initialze the data area
  193. dp = orgDataPtr;
  194. goto initLabel;
  195. }
  196. // expansion was requested
  197. }
  198. // if an empty data area was requested
  199. if( newByteCnt == 0 )
  200. return NULL;
  201. //
  202. // A new data block must be allocated
  203. //
  204. // allocate the memory block via a callback
  205. if((bp = p->allocFunc(p->funcArgPtr,ttlByteCnt)) == NULL )
  206. {
  207. cmErrMsg(&p->err,kAllocFailMmRC,"Attempt to allocate %i bytes failed.",ttlByteCnt);
  208. goto errLabel;
  209. }
  210. // make the data area offset: data_byte_cnt + guard bytes
  211. dp = bp + (2*sizeof(unsigned)) + gbc;
  212. if( abc )
  213. {
  214. unsigned long alignMask = abc - 1;
  215. // alignment requires an additional offset
  216. dp += abc;
  217. // align the data area to the specified boundary
  218. char* ndp = ((char*)((unsigned long)dp & (~alignMask)));
  219. prefixByteCnt = abc - (dp - ndp);
  220. dp = ndp;
  221. }
  222. // set the prefix byteCnt
  223. *(unsigned*)_cmMmDataToPrefixCntPtr(dp,gbc) = prefixByteCnt;
  224. // set the data area byte cnt
  225. *(unsigned*)_cmMmDataToByteCntPtr(dp,gbc) = newByteCnt;
  226. // uncomment this line to print memory layout information for each block
  227. //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);
  228. // set the guard bytes
  229. if( gbc )
  230. {
  231. void* gp = _cmMmDataToPreGuardPtr( dp,gbc);
  232. if( gp != NULL )
  233. memset(gp, p->guardChar, gbc);
  234. gp = _cmMmDataToPostGuardPtr( dp,gbc);
  235. if( gp != NULL )
  236. memset(gp, p->guardChar, gbc);
  237. }
  238. initLabel:
  239. //
  240. // initialize the new data area
  241. //
  242. idp = dp;
  243. // if this is a reallocation with expansion ...
  244. if( orgDataPtr != NULL && newByteCnt > orgByteCnt )
  245. {
  246. // ... and preservation was requested
  247. if( cmIsFlag(flags,kPreserveMmFl) )
  248. {
  249. // copy original data into the new block
  250. memcpy(idp,orgDataPtr,orgByteCnt);
  251. idp += orgByteCnt;
  252. newByteCnt -= orgByteCnt;
  253. }
  254. _cmMmFreeP(p,orgDataPtr); // free the original data block
  255. }
  256. // if zeroing was requested
  257. if( cmIsFlag(flags,kZeroMmFl))
  258. memset(idp,0,newByteCnt);
  259. else
  260. // if uninitialized data should be set to a known character
  261. if( cmIsFlag(p->flags,kFillUninitMmFl) )
  262. memset(idp,p->uninitChar,newByteCnt);
  263. return dp;
  264. errLabel:
  265. return NULL;
  266. }
  267. cmMmRC_t cmMmInitialize(
  268. cmMmH_t* hp,
  269. cmAllocMmFunc_t allocFunc,
  270. cmFreeMmFunc_t freeFunc,
  271. void* funcArgPtr,
  272. unsigned guardByteCnt,
  273. unsigned alignByteCnt,
  274. unsigned flags,
  275. cmRpt_t* rpt )
  276. {
  277. cmMm_t* p;
  278. cmErr_t err;
  279. cmErrSetup(&err,rpt,"Memory Manager");
  280. // validate alignByteCnt
  281. if(alignByteCnt>0 && cmIsPowerOfTwo(alignByteCnt)==false)
  282. return cmErrMsg(&err,kParamErrMmRC,"The 'alignByteCnt' parameter must be a power of two.");
  283. // allocate the main object
  284. if((p= calloc(1,sizeof(cmMm_t))) == NULL )
  285. return cmErrMsg(&err,kObjAllocFailMmRC,"Object allocation failed.");
  286. // setting kDeferFreeMmFl only makes sense when kTrackMmFl is also set
  287. if(cmIsFlag(flags,kTrackMmFl)==false && cmIsFlag(flags,kDeferFreeMmFl)==true)
  288. {
  289. cmErrMsg(&err,kParamErrMmRC,"The flag 'kDeferFreeMmFl' may only be set if the 'kTrackMmFl' is also set. 'kDeferFreeMmFl' is begin disabled.");
  290. flags = cmClrFlag(flags,kDeferFreeMmFl);
  291. }
  292. cmErrClone(&p->err,&err);
  293. p->rpt = rpt;
  294. p->alignByteCnt = alignByteCnt;
  295. p->guardByteCnt = guardByteCnt;
  296. p->allocFunc = allocFunc;
  297. p->freeFunc = freeFunc;
  298. p->funcArgPtr = funcArgPtr;
  299. p->uninitChar = 0x55; // non-zeroed data areas are automatically filled w/ this value on allocation
  300. p->freeChar = 0x33; // data areas are overwritten with this value on free
  301. p->guardChar = 0xAA; // guard areas are set with this value
  302. p->flags = flags;
  303. hp->h = p;
  304. return kOkMmRC;
  305. }
  306. cmMmRC_t cmMmFinalize( cmMmH_t* hp )
  307. {
  308. cmMm_t* p;
  309. cmMmRC_t rc = kOkMmRC;
  310. if( hp == NULL || cmMmIsValid(*hp)==false )
  311. return kOkMmRC;
  312. p = _cmMmHandleToPtr(*hp);
  313. cmMmRecd_t* rp = p->listPtr;
  314. while( rp != NULL )
  315. {
  316. cmMmRecd_t* tp = rp->linkPtr;
  317. cmMmRC_t rrc;
  318. if( cmIsFlag(p->flags,kDeferFreeMmFl) )
  319. if((rrc = _cmMmFree(p,rp->dataPtr,rp)) != kOkMmRC )
  320. rc = rrc;
  321. free(rp);
  322. rp = tp;
  323. }
  324. free(p);
  325. hp->h = NULL;
  326. return rc;
  327. }
  328. unsigned cmMmGuardByteCount( cmMmH_t h )
  329. {
  330. cmMm_t* p = _cmMmHandleToPtr(h);
  331. return p->guardByteCnt;
  332. }
  333. unsigned cmMmAlignByteCount( cmMmH_t h )
  334. {
  335. cmMm_t* p = _cmMmHandleToPtr(h);
  336. return p->alignByteCnt;
  337. }
  338. unsigned cmMmInitializeFlags( cmMmH_t h )
  339. {
  340. cmMm_t* p = _cmMmHandleToPtr(h);
  341. return p->flags;
  342. }
  343. bool cmMmIsValid( cmMmH_t h )
  344. { return h.h != NULL; }
  345. void* cmMmAllocate(
  346. cmMmH_t h,
  347. void* orgDataPtr,
  348. unsigned newEleCnt,
  349. unsigned newEleByteCnt,
  350. enum cmMmAllocFlags_t flags,
  351. const char* fileName,
  352. const char* funcName,
  353. unsigned fileLine )
  354. {
  355. cmMm_t* p = _cmMmHandleToPtr(h);
  356. unsigned newByteCnt = newEleCnt * newEleByteCnt;
  357. void* ndp = _cmMmAllocate(p,orgDataPtr,newByteCnt,flags);
  358. /*
  359. if( p->nextId == 189114 )
  360. {
  361. cmErrMsg(&p->err,kOkMmRC,"Breakpoint for memory allocation id:%i.",p->nextId);
  362. }
  363. */
  364. // if we are tracking changes
  365. if( cmIsFlag(p->flags,kTrackMmFl) )
  366. {
  367. //
  368. // NOTE: it is possible that ndp is NULL if newByteCnt == 0.
  369. //
  370. cmMmRecd_t* rp = NULL;
  371. // if a new memory block was allocated
  372. if( orgDataPtr == NULL || orgDataPtr != ndp )
  373. {
  374. // allocate a new tracking recd
  375. if( (rp = calloc(1,sizeof(cmMmRecd_t))) == NULL )
  376. {
  377. cmErrMsg(&p->err,kTrkAllocFailMmRC,"Unable to allocate a tracking record for %s line:%i %s.",funcName,fileLine,fileName);
  378. return ndp;
  379. }
  380. // initialize the new tracking recd
  381. rp->uniqueId = p->nextId;
  382. rp->dataPtr = ndp;
  383. rp->dataByteCnt = newByteCnt;
  384. rp->fileLine = fileLine;
  385. rp->fileNameStr = fileName;
  386. rp->funcNameStr = funcName;
  387. rp->flags = 0;
  388. rp->linkPtr = p->listPtr;
  389. //printf("%i %i %s %i %s\n",rp->uniqueId,newByteCnt,funcName,fileLine,fileName);
  390. p->listPtr = rp;
  391. assert( _cmMmCheckGuards(p,rp) == kOkMmRC );
  392. ++p->nextId;
  393. }
  394. else // a reallocation occurred.
  395. if( orgDataPtr == ndp )
  396. {
  397. if((rp = _cmMmFindRecd(p,orgDataPtr)) == NULL )
  398. cmErrMsg(&p->err,kMissingRecdMmRC,"Unable to locate a tracking record associated with reallocation data area pointer:%p.",orgDataPtr);
  399. }
  400. }
  401. return ndp;
  402. }
  403. cmMmRC_t cmMmFree( cmMmH_t h, void* dataPtr )
  404. {
  405. cmMm_t* p = _cmMmHandleToPtr(h);
  406. return _cmMmFreeP(p,dataPtr);
  407. }
  408. cmMmRC_t cmMmFreeDebug( cmMmH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine )
  409. {
  410. cmMmRC_t rc;
  411. if((rc = cmMmFree(h,dataPtr)) != kOkMmRC )
  412. cmErrMsg(&_cmMmHandleToPtr(h)->err,rc,"Memory free failed at %s() line:%i %s",funcName,fileLine,fileName);
  413. return rc;
  414. }
  415. cmMmRC_t cmMmFreePtr( cmMmH_t h, void** dataPtrPtr )
  416. {
  417. assert(dataPtrPtr != NULL );
  418. cmMmRC_t rc = cmMmFree(h,*dataPtrPtr);
  419. *dataPtrPtr = NULL;
  420. return rc;
  421. }
  422. cmMmRC_t cmMmFreePtrDebug( cmMmH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine )
  423. {
  424. cmMmRC_t rc;
  425. if((rc = cmMmFreePtr(h,dataPtr)) != kOkMmRC )
  426. cmErrMsg(&_cmMmHandleToPtr(h)->err,rc,"Memory free failed at %s() line:%i %s",funcName,fileLine,fileName);
  427. return rc;
  428. }
  429. unsigned cmMmByteCount( cmMmH_t h, const void* dataPtr )
  430. {
  431. cmMm_t* p = _cmMmHandleToPtr(h);
  432. return _cmMmDataToByteCnt(dataPtr,p->guardByteCnt);
  433. }
  434. unsigned cmMmDebugId( cmMmH_t h, const void* dataPtr)
  435. {
  436. cmMm_t* p = _cmMmHandleToPtr(h);
  437. const cmMmRecd_t* rp = NULL;
  438. // if we are tracking alloc's and free's
  439. if( cmIsFlag(p->flags,kTrackMmFl) )
  440. {
  441. // locate the tracking recd
  442. rp = _cmMmFindRecd(p,dataPtr);
  443. }
  444. return rp==NULL ? cmInvalidId : rp->uniqueId;
  445. }
  446. cmMmRC_t _cmMmError( cmMm_t* p, cmMmRC_t rc, const cmMmRecd_t* rp, const char* msg )
  447. {
  448. 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);
  449. }
  450. cmMmRC_t _cmMmRecdPrint( cmMm_t* p, cmMmRecd_t* rp, cmMmRC_t rc )
  451. {
  452. void* dp = rp->dataPtr;
  453. unsigned gbc = p->guardByteCnt;
  454. char* lbl = NULL;
  455. switch( rc )
  456. {
  457. case kOkMmRC: lbl = "Ok "; break;
  458. case kLeakDetectedMmRC: lbl = "Memory Leak "; break;
  459. case kWriteAfterFreeMmRC: lbl = "Write After Free"; break;
  460. case kDblFreeDetectedMmRC: lbl = "Double Free "; break;
  461. case kGuardCorruptMmRC: lbl = "Guard Corrupt "; break;
  462. default:
  463. lbl = "Unknown Status ";
  464. }
  465. cmRptPrintf(p->err.rpt,"%s id:%5i data:%p : data:%5i prefix:%5i total:%5i base:%p : %5i %s %s\n",
  466. lbl,rp->uniqueId,rp->dataPtr,
  467. _cmMmDataToByteCnt(dp,gbc),
  468. _cmMmDataToPrefixCnt(dp,gbc),
  469. _cmMmDataToTotalByteCnt(dp,gbc),
  470. _cmMmDataToBasePtr(dp,gbc),
  471. rp->fileLine,rp->funcNameStr,rp->fileNameStr );
  472. return rc;
  473. }
  474. cmMmRC_t cmMmReport( cmMmH_t h, unsigned flags )
  475. {
  476. cmMm_t* p = _cmMmHandleToPtr(h);
  477. unsigned allocByteCnt = 0;
  478. unsigned ttlByteCnt = 0;
  479. unsigned dataFrByteCnt = 0;
  480. unsigned ttlFrByteCnt = 0;
  481. unsigned dataLkByteCnt = 0;
  482. unsigned ttlLkByteCnt = 0;
  483. unsigned allocBlkCnt = 0;
  484. unsigned freeBlkCnt = 0;
  485. unsigned leakBlkCnt = 0;
  486. cmMmRecd_t* rp = p->listPtr;
  487. cmMmRC_t ret_rc = kOkMmRC;
  488. for(; rp != NULL; rp = rp->linkPtr,++allocBlkCnt )
  489. {
  490. cmMmRC_t rc = kOkMmRC;
  491. unsigned blkDataByteCnt = _cmMmDataToByteCnt(rp->dataPtr,p->guardByteCnt);
  492. unsigned blkTtlByteCnt = _cmMmDataToTotalByteCnt(rp->dataPtr,p->guardByteCnt);
  493. allocByteCnt += blkDataByteCnt;
  494. ttlByteCnt += blkTtlByteCnt;
  495. // if this block was freed or never alloc'd
  496. if( cmIsFlag(rp->flags,kFreedMmFl) || rp->dataPtr == NULL )
  497. {
  498. ++freeBlkCnt;
  499. dataFrByteCnt += blkDataByteCnt;
  500. ttlFrByteCnt += blkTtlByteCnt;
  501. }
  502. else // if this block leaked
  503. {
  504. ++leakBlkCnt;
  505. dataLkByteCnt += blkDataByteCnt;
  506. ttlLkByteCnt += blkTtlByteCnt;
  507. if( cmIsFlag(flags,kIgnoreLeaksMmFl) == false )
  508. rc = _cmMmRecdPrint(p,rp,kLeakDetectedMmRC);
  509. }
  510. // if this block was double freed
  511. if( cmIsFlag(rp->flags,kDblFreeMmFl) )
  512. rc = _cmMmRecdPrint(p,rp,kDblFreeDetectedMmRC);
  513. // check for guard corruption and write-after-free
  514. cmMmRC_t t_rc = _cmMmCheckGuards(p,rp);
  515. switch( t_rc )
  516. {
  517. case kOkMmRC:
  518. break;
  519. case kGuardCorruptMmRC:
  520. rc = _cmMmRecdPrint(p,rp,t_rc);
  521. break;
  522. case kWriteAfterFreeMmRC:
  523. rc = _cmMmRecdPrint(p,rp,t_rc);
  524. break;
  525. default:
  526. assert(0);
  527. break;
  528. }
  529. if( rc != kOkMmRC )
  530. ret_rc = rc;
  531. else
  532. {
  533. if( cmIsFlag(flags,kIgnoreNormalMmFl)==false )
  534. _cmMmRecdPrint(p,rp,rc);
  535. }
  536. }
  537. if( p->listPtr != NULL && cmIsFlag(flags,kSuppressSummaryMmFl)==false )
  538. {
  539. cmRptPrintf(p->err.rpt,"Blocks Allocated:%i Freed:%i Leaked:%i\n",allocBlkCnt,freeBlkCnt,leakBlkCnt);
  540. 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);
  541. }
  542. return ret_rc;
  543. }
  544. cmMmRC_t cmMmIsGuardCorrupt( cmMmH_t h, unsigned id )
  545. {
  546. cmMm_t* p = _cmMmHandleToPtr(h);
  547. cmMmRecd_t* rp = p->listPtr;
  548. while(rp != NULL )
  549. {
  550. if( rp->uniqueId == id )
  551. break;
  552. rp = rp->linkPtr;
  553. }
  554. if( rp == NULL )
  555. return cmErrMsg(&p->err,kMissingRecdMmRC,"Unable to locate the tracking record associated with id %i.",id);
  556. return _cmMmCheckGuards(p,rp);
  557. }
  558. cmMmRC_t cmMmCheckAllGuards( cmMmH_t h )
  559. {
  560. cmMm_t* p = _cmMmHandleToPtr(h);
  561. cmMmRecd_t* rp = p->listPtr;
  562. cmMmRC_t rc = kOkMmRC;
  563. while(rp != NULL )
  564. {
  565. if((rc = _cmMmCheckGuards(p,rp)) != kOkMmRC )
  566. 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);
  567. rp = rp->linkPtr;
  568. }
  569. return rc;
  570. }