libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cmMem.c 20KB

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