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