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 20KB

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