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.

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