libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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. }