libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmMem.c 21KB

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