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

cmMem.c 19KB

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