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

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