context.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. #include <string.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. #include "private.h"
  7. #include "context.h"
  8. #include "node.h"
  9. unsigned long lub_heap_frame_count;
  10. #define CONTEXT_CHUNK_SIZE 100 /* number of contexts per chunk */
  11. #define CONTEXT_MAX_CHUNKS 100 /* allow upto 10000 contexts */
  12. /*---------------------------------------------------------
  13. * PRIVATE META FUNCTIONS
  14. *--------------------------------------------------------- */
  15. void lub_heap_context_meta_init(void)
  16. {
  17. static bool_t initialised = BOOL_FALSE;
  18. if (BOOL_FALSE == initialised) {
  19. lub_heap_leak_t *leak = lub_heap_leak_instance();
  20. initialised = BOOL_TRUE;
  21. /* initialise the context tree */
  22. lub_bintree_init(&leak->m_context_tree,
  23. offsetof(lub_heap_context_t, bt_node),
  24. lub_heap_context_compare,
  25. lub_heap_context_getkey);
  26. lub_heap_leak_release(leak);
  27. }
  28. }
  29. /*--------------------------------------------------------- */
  30. int lub_heap_context_compare(const void *clientnode, const void *clientkey)
  31. {
  32. int i, delta = 0;
  33. const lub_heap_context_t *node = clientnode;
  34. const lub_heap_context_key_t *key = clientkey;
  35. function_t *const *node_fn = node->key.backtrace;
  36. function_t *const *key_fn = key->backtrace;
  37. for (i = lub_heap_frame_count; i; --i, ++node_fn, ++key_fn) {
  38. delta = ((unsigned long)*node_fn - (unsigned long)*key_fn);
  39. if (0 != delta) {
  40. break;
  41. }
  42. }
  43. return delta;
  44. }
  45. /*--------------------------------------------------------- */
  46. /* we simply use the embedded key as the index */
  47. void lub_heap_context_getkey(const void *clientnode, lub_bintree_key_t * key)
  48. {
  49. const lub_heap_context_t *context = clientnode;
  50. memcpy(key, &context->key, sizeof(lub_heap_context_key_t));
  51. }
  52. /*--------------------------------------------------------- */
  53. static bool_t
  54. lub_heap_foreach_context(bool_t(*fn) (lub_heap_context_t *, void *), void *arg)
  55. {
  56. bool_t result = BOOL_FALSE;
  57. lub_heap_context_t *context;
  58. lub_bintree_iterator_t iter;
  59. lub_heap_context_meta_init();
  60. {
  61. lub_heap_leak_t *leak = lub_heap_leak_instance();
  62. for (context = lub_bintree_findfirst(&leak->m_context_tree),
  63. context ? lub_bintree_iterator_init(&iter,
  64. &leak->m_context_tree,
  65. context) : (void)0;
  66. context; context = lub_bintree_iterator_next(&iter)) {
  67. lub_heap_leak_release(leak);
  68. /* invoke the specified method on this context */
  69. result = fn(context, arg);
  70. leak = lub_heap_leak_instance();
  71. }
  72. lub_heap_leak_release(leak);
  73. }
  74. return result;
  75. }
  76. /*--------------------------------------------------------- */
  77. static void lub_heap_show_summary(void)
  78. {
  79. lub_heap_leak_t *leak = lub_heap_leak_instance();
  80. size_t ok_allocs = leak->m_stats.allocs;
  81. size_t ok_bytes = leak->m_stats.alloc_bytes;
  82. size_t ok_overhead = leak->m_stats.alloc_overhead;
  83. ok_allocs -= leak->m_stats.partials;
  84. ok_allocs -= leak->m_stats.leaks;
  85. ok_overhead -= leak->m_stats.partial_overhead;
  86. ok_overhead -= leak->m_stats.leaked_overhead;
  87. printf("\n"
  88. " +----------+----------+----------+----------+\n");
  89. printf(" TOTALS | blocks| bytes| average| overhead|\n");
  90. printf("+---------+----------+----------+----------+----------+\n");
  91. printf("|contexts |%10" SIZE_FMT "|%10" SIZE_FMT "|%10" SIZE_FMT
  92. "|%10s|\n", leak->m_stats.contexts,
  93. leak->m_stats.contexts * sizeof(lub_heap_context_t),
  94. leak->m_stats.contexts ? sizeof(lub_heap_context_t) : 0, "");
  95. printf("|allocs |%10" SIZE_FMT "|%10" SIZE_FMT "|%10" SIZE_FMT "|%10"
  96. SIZE_FMT "|\n", ok_allocs, ok_bytes,
  97. ok_allocs ? (ok_bytes / ok_allocs) : 0, ok_overhead);
  98. if (leak->m_stats.partials) {
  99. printf("|partials |%10" SIZE_FMT "|%10" SIZE_FMT "|%10" SIZE_FMT
  100. "|%10" SIZE_FMT "|\n", leak->m_stats.partials,
  101. leak->m_stats.partial_bytes,
  102. leak->m_stats.partials ? (leak->m_stats.partial_bytes /
  103. leak->m_stats.partials) : 0,
  104. leak->m_stats.partial_overhead);
  105. }
  106. if (leak->m_stats.leaks) {
  107. printf("|leaks |%10" SIZE_FMT "|%10" SIZE_FMT "|%10" SIZE_FMT
  108. "|%10" SIZE_FMT "|\n", leak->m_stats.leaks,
  109. leak->m_stats.leaked_bytes,
  110. leak->m_stats.leaks ? (leak->m_stats.leaked_bytes /
  111. leak->m_stats.leaks) : 0,
  112. leak->m_stats.leaked_overhead);
  113. }
  114. printf("+---------+----------+----------+----------+----------+\n");
  115. lub_heap_leak_release(leak);
  116. }
  117. /*--------------------------------------------------------- */
  118. /*---------------------------------------------------------
  119. * PRIVATE METHODS
  120. *--------------------------------------------------------- */
  121. static void
  122. lub_heap_context_foreach_node(lub_heap_context_t * this,
  123. void (*fn) (lub_heap_node_t *))
  124. {
  125. lub_heap_node_t *node;
  126. for (node = this->first_node;
  127. node; node = lub_heap_node__get_next(node)) {
  128. /* invoke the specified method on this node */
  129. fn(node);
  130. }
  131. }
  132. /*--------------------------------------------------------- */
  133. /*---------------------------------------------------------
  134. * PUBLIC METHODS
  135. *--------------------------------------------------------- */
  136. void
  137. lub_heap_context_init(lub_heap_context_t * this,
  138. lub_heap_t * heap, const stackframe_t * stack)
  139. {
  140. lub_heap_context_meta_init();
  141. this->heap = heap;
  142. this->allocs = 0;
  143. this->alloc_bytes = 0;
  144. this->alloc_overhead = 0;
  145. this->leaks = 0;
  146. this->leaked_bytes = 0;
  147. this->leaked_overhead = 0;
  148. this->partials = 0;
  149. this->partial_bytes = 0;
  150. this->partial_overhead = 0;
  151. this->first_node = NULL;
  152. /* set the current backtrace for the context */
  153. this->key = *stack;
  154. /* intialise this context's binary tree node */
  155. lub_bintree_node_init(&this->bt_node);
  156. {
  157. lub_heap_leak_t *leak = lub_heap_leak_instance();
  158. /* add this context to the context_tree */
  159. lub_bintree_insert(&leak->m_context_tree, this);
  160. lub_heap_leak_release(leak);
  161. }
  162. }
  163. /*--------------------------------------------------------- */
  164. void lub_heap_context_fini(lub_heap_context_t * this)
  165. {
  166. lub_heap_leak_t *leak = lub_heap_leak_instance();
  167. /* remove this node from the context_tree */
  168. lub_bintree_remove(&leak->m_context_tree, this);
  169. lub_heap_leak_release(leak);
  170. /* cleanup the context */
  171. lub_heap_context_clear(this);
  172. }
  173. /*--------------------------------------------------------- */
  174. void
  175. lub_heap_context_insert_node(lub_heap_context_t * this, lub_heap_node_t * node)
  176. {
  177. /* add the node to the linked list */
  178. lub_heap_node__set_next(node, this->first_node);
  179. node->prev = NULL;
  180. if (this->first_node) {
  181. this->first_node->prev = node;
  182. }
  183. this->first_node = node;
  184. }
  185. /*--------------------------------------------------------- */
  186. void
  187. lub_heap_context_remove_node(lub_heap_context_t * this, lub_heap_node_t * node)
  188. {
  189. lub_heap_node_t *next, *prev = NULL;
  190. /* remove the node from the context list */
  191. next = lub_heap_node__get_next(node);
  192. prev = node->prev;
  193. if (NULL == prev) {
  194. this->first_node = next;
  195. } else {
  196. lub_heap_node__set_next(prev, next);
  197. }
  198. if (NULL != next) {
  199. next->prev = prev;
  200. }
  201. /* clear the pointers */
  202. lub_heap_node__set_next(node, NULL);
  203. node->prev = NULL;
  204. /* is this the last node in a context? */
  205. if (0 == this->allocs) {
  206. /* removing the last node deletes the context */
  207. lub_heap_context_delete(this);
  208. }
  209. }
  210. /*--------------------------------------------------------- */
  211. void lub_heap_context_show_frame(lub_heap_context_t * this, int frame)
  212. {
  213. if (frame >= 0) {
  214. long address = (long)this->key.backtrace[frame];
  215. if (address) {
  216. lub_heap_symShow(address);
  217. }
  218. }
  219. printf("\n");
  220. }
  221. /*--------------------------------------------------------- */
  222. void lub_heap_node_post(lub_heap_node_t * node)
  223. {
  224. /* assume the worst */
  225. if (BOOL_TRUE == lub_heap_node__get_leaked(node)) {
  226. /* this is a full leak */
  227. lub_heap_node__set_partial(node, BOOL_FALSE);
  228. }
  229. }
  230. /*--------------------------------------------------------- */
  231. void lub_heap_node_prep(lub_heap_node_t * node, void *arg)
  232. {
  233. /* assume the worst */
  234. lub_heap_node__set_leaked(node, BOOL_TRUE);
  235. lub_heap_node__set_partial(node, BOOL_TRUE);
  236. lub_heap_node__set_scanned(node, BOOL_FALSE);
  237. }
  238. /*--------------------------------------------------------- */
  239. void lub_heap_node_scan(lub_heap_node_t * node, void *arg)
  240. {
  241. /* only scan nodes which have references */
  242. if ((BOOL_FALSE == lub_heap_node__get_leaked(node))
  243. && (BOOL_FALSE == lub_heap_node__get_scanned(node))) {
  244. lub_heap_node__set_scanned(node, BOOL_TRUE);
  245. lub_heap_scan_memory(lub_heap_node__get_ptr(node),
  246. lub_heap_node__get_size(node));
  247. }
  248. }
  249. /*--------------------------------------------------------- */
  250. static bool_t lub_heap_context_prep(lub_heap_context_t * this, void *arg)
  251. {
  252. /* start off by assuming the worst */
  253. this->partials = this->leaks = this->allocs;
  254. this->partial_bytes = this->leaked_bytes = this->alloc_bytes;
  255. this->partial_overhead = this->leaked_overhead = this->alloc_overhead;
  256. {
  257. lub_heap_leak_t *leak = lub_heap_leak_instance();
  258. /* initialised the global stats */
  259. leak->m_stats.allocs += this->allocs;
  260. leak->m_stats.alloc_bytes += this->alloc_bytes;
  261. leak->m_stats.alloc_overhead += this->alloc_overhead;
  262. lub_heap_leak_release(leak);
  263. }
  264. return BOOL_TRUE;
  265. }
  266. /*--------------------------------------------------------- */
  267. static bool_t lub_heap_context_post(lub_heap_context_t * this, void *arg)
  268. {
  269. /* don't count full leaks as partials */
  270. this->partials -= this->leaks;
  271. this->partial_bytes -= this->leaked_bytes;
  272. this->partial_overhead -= this->leaked_overhead;
  273. /* post process the contained nodes */
  274. lub_heap_context_foreach_node(this, lub_heap_node_post);
  275. return BOOL_TRUE;
  276. }
  277. /*--------------------------------------------------------- */
  278. static void scan_segment(void *ptr, unsigned index, size_t size, void *arg)
  279. {
  280. lub_heap_segment_t *segment = ptr;
  281. const char *memory = (const char *)lub_heap_block_getfirst(segment);
  282. /* now scan the memory in this segment */
  283. printf(".");
  284. lub_heap_scan_memory(memory, size);
  285. }
  286. /*--------------------------------------------------------- */
  287. /**
  288. * This function scans all the nodes currently allocated in the
  289. * system for references to other allocated nodes.
  290. * First of all we mark all nodes as leaked, then scan all the nodes
  291. * for any references to other ones. If found those other ones
  292. * are cleared from being leaked.
  293. * At the end of the process all nodes which are leaked then
  294. * update their context leak count.
  295. */
  296. void lub_heap_scan_all(void)
  297. {
  298. lub_heap_t *heap;
  299. lub_heap_leak_t *leak = lub_heap_leak_instance();
  300. /* clear the summary stats */
  301. memset(&leak->m_stats, 0, sizeof(leak->m_stats));
  302. lub_heap_leak_release(leak);
  303. /* first of all prepare the contexts for scanning */
  304. lub_heap_foreach_context(lub_heap_context_prep, 0);
  305. /* then prepare all the nodes (including those who have no context) */
  306. lub_heap_foreach_node(lub_heap_node_prep, 0);
  307. printf(" Scanning memory");
  308. /* clear out the stacks in the system */
  309. lub_heap_clean_stacks();
  310. /* Scan the current stack */
  311. printf(".");
  312. lub_heap_scan_stack();
  313. /* Scan the BSS segment */
  314. printf(".");
  315. lub_heap_scan_bss();
  316. /* Scan the DATA segment */
  317. printf(".");
  318. lub_heap_scan_data();
  319. /* Scan the non-monitored blocks which are allocated in the system */
  320. leak = lub_heap_leak_instance();
  321. for (heap = leak->m_heap_list; heap; heap = heap->next) {
  322. lub_heap_leak_release(leak);
  323. lub_heap_foreach_segment(heap, scan_segment, 0);
  324. leak = lub_heap_leak_instance();
  325. }
  326. lub_heap_leak_release(leak);
  327. /*
  328. * now scan the nodes NB. only referenced nodes will be scanned
  329. * we loop until we stop scanning new nodes
  330. */
  331. leak = lub_heap_leak_instance();
  332. do {
  333. leak->m_stats.scanned = 0;
  334. /* scan each node */
  335. lub_heap_leak_release(leak);
  336. printf(".");
  337. lub_heap_foreach_node(lub_heap_node_scan, NULL);
  338. leak = lub_heap_leak_instance();
  339. } while (leak->m_stats.scanned);
  340. printf("done\n\n");
  341. /* post process each context and contained nodes */
  342. lub_heap_leak_release(leak);
  343. lub_heap_foreach_context(lub_heap_context_post, 0);
  344. leak = lub_heap_leak_instance();
  345. lub_heap_leak_release(leak);
  346. }
  347. /*--------------------------------------------------------- */
  348. void lub_heap_node_show(lub_heap_node_t * node)
  349. {
  350. printf("%s%p[%" SIZE_FMT "] ",
  351. lub_heap_node__get_leaked(node) ? "*" :
  352. lub_heap_node__get_partial(node) ? "+" : "",
  353. lub_heap_node__get_ptr(node), lub_heap_node__get_size(node));
  354. }
  355. /*--------------------------------------------------------- */
  356. static bool_t
  357. lub_heap_context_match(lub_heap_context_t * this, const char *substring)
  358. {
  359. bool_t result = BOOL_TRUE;
  360. if (substring) {
  361. int i;
  362. long address;
  363. result = BOOL_FALSE;
  364. /*
  365. * search the stacktrace for this context
  366. * to see whether it matches
  367. */
  368. for (i = 0; (address = (long)this->key.backtrace[i]); ++i) {
  369. if (lub_heap_symMatch(address, substring)) {
  370. result = BOOL_TRUE;
  371. break;
  372. }
  373. }
  374. }
  375. return result;
  376. }
  377. /*--------------------------------------------------------- */
  378. typedef struct {
  379. lub_heap_show_e how;
  380. const char *substring;
  381. } context_show_arg_t;
  382. /*--------------------------------------------------------- */
  383. bool_t lub_heap_context_show_fn(lub_heap_context_t * this, void *arg)
  384. {
  385. bool_t result = BOOL_FALSE;
  386. context_show_arg_t *show_arg = arg;
  387. lub_heap_leak_t *leak = lub_heap_leak_instance();
  388. /* add in the context details */
  389. ++leak->m_stats.contexts;
  390. leak->m_stats.allocs += this->allocs;
  391. leak->m_stats.alloc_bytes += this->alloc_bytes;
  392. leak->m_stats.alloc_overhead += this->alloc_overhead;
  393. leak->m_stats.partials += this->partials;
  394. leak->m_stats.partial_bytes += this->partial_bytes;
  395. leak->m_stats.partial_overhead += this->partial_overhead;
  396. leak->m_stats.leaks += this->leaks;
  397. leak->m_stats.leaked_bytes += this->leaked_bytes;
  398. leak->m_stats.leaked_overhead += this->leaked_overhead;
  399. lub_heap_leak_release(leak);
  400. if (lub_heap_context_match(this, show_arg->substring)) {
  401. result = lub_heap_context_show(this, show_arg->how);
  402. }
  403. return result;
  404. }
  405. /*--------------------------------------------------------- */
  406. bool_t lub_heap_context_show(lub_heap_context_t * this, lub_heap_show_e how)
  407. {
  408. long frame = lub_heap_frame_count - 1;
  409. size_t ok_allocs = this->allocs;
  410. size_t ok_bytes = this->alloc_bytes;
  411. size_t ok_overhead = this->alloc_overhead;
  412. ok_allocs -= this->partials;
  413. ok_allocs -= this->leaks;
  414. ok_bytes -= this->partial_bytes;
  415. ok_bytes -= this->leaked_bytes;
  416. ok_overhead -= this->partial_overhead;
  417. ok_overhead -= this->leaked_overhead;
  418. switch (how) {
  419. case LUB_HEAP_SHOW_ALL:
  420. {
  421. /* show everything */
  422. break;
  423. }
  424. case LUB_HEAP_SHOW_PARTIALS:
  425. {
  426. if (0 < this->partials) {
  427. /* there's at least one partial in this context */
  428. break;
  429. }
  430. /*lint -e(616) fall through */
  431. }
  432. case LUB_HEAP_SHOW_LEAKS:
  433. {
  434. if (0 < this->leaks) {
  435. /* there's at least one leak in this context */
  436. break;
  437. }
  438. /*lint -e(616) fall through */
  439. }
  440. default:
  441. {
  442. /* nothing to be shown */
  443. return BOOL_FALSE;
  444. }
  445. }
  446. /* find the top of the stack trace */
  447. while ((frame >= 0) && (0 == this->key.backtrace[frame])) {
  448. --frame;
  449. }
  450. printf(" +----------+----------+----------+----------+");
  451. lub_heap_context_show_frame(this, frame--);
  452. printf("%10p| blocks| bytes| average| overhead|",
  453. (void *)this);
  454. lub_heap_context_show_frame(this, frame--);
  455. printf("+---------+----------+----------+----------+----------+");
  456. lub_heap_context_show_frame(this, frame--);
  457. printf("|allocs |%10" SIZE_FMT "|%10" SIZE_FMT "|%10" SIZE_FMT "|%10"
  458. SIZE_FMT "|", ok_allocs, ok_bytes,
  459. ok_allocs ? (ok_bytes / ok_allocs) : 0, ok_overhead);
  460. lub_heap_context_show_frame(this, frame--);
  461. if (this->partials) {
  462. printf("|partials |%10" SIZE_FMT "|%10" SIZE_FMT "|%10" SIZE_FMT
  463. "|%10" SIZE_FMT "|", this->partials, this->partial_bytes,
  464. this->partials ? (this->partial_bytes /
  465. this->partials) : 0,
  466. this->partial_overhead);
  467. lub_heap_context_show_frame(this, frame--);
  468. }
  469. if (this->leaks) {
  470. printf("|leaks |%10" SIZE_FMT "|%10" SIZE_FMT "|%10" SIZE_FMT
  471. "|%10" SIZE_FMT "|", this->leaks, this->leaked_bytes,
  472. this->leaks ? (this->leaked_bytes / this->leaks) : 0,
  473. this->leaked_overhead);
  474. lub_heap_context_show_frame(this, frame--);
  475. }
  476. printf("+---------+----------+----------+----------+----------+");
  477. lub_heap_context_show_frame(this, frame--);
  478. while (frame >= 0) {
  479. printf("%55s", "");
  480. lub_heap_context_show_frame(this, frame--);
  481. }
  482. printf("ALLOCATED BLOCKS: ");
  483. /* now iterate the allocated nodes */
  484. lub_heap_context_foreach_node(this, lub_heap_node_show);
  485. printf("\n\n");
  486. return BOOL_TRUE;
  487. }
  488. /*--------------------------------------------------------- */
  489. void lub_heap_context_clear(lub_heap_context_t * this)
  490. {
  491. /* should only ever get cleared when all nodes have left the context */
  492. assert(0 == this->first_node);
  493. this->heap = 0;
  494. /* reset the counters */
  495. this->allocs = 0;
  496. this->alloc_bytes = 0;
  497. this->leaks = 0;
  498. this->leaked_bytes = 0;
  499. this->partials = 0;
  500. this->partial_bytes = 0;
  501. }
  502. /*--------------------------------------------------------- */
  503. void lub_heap_show_leak_trees(void)
  504. {
  505. lub_heap_leak_t *leak = lub_heap_leak_instance();
  506. printf("context_tree : ");
  507. lub_bintree_dump(&leak->m_context_tree);
  508. printf("\n");
  509. printf("node_tree : ");
  510. lub_bintree_dump(&leak->m_node_tree);
  511. printf("\n");
  512. printf("clear_node_tree: ");
  513. lub_bintree_dump(&leak->m_clear_node_tree);
  514. printf("\n");
  515. lub_heap_leak_release(leak);
  516. }
  517. /*--------------------------------------------------------- */
  518. void lub_heap_leak_scan(void)
  519. {
  520. if (0 < lub_heap_frame_count) {
  521. /* check for memory leaks */
  522. if (!lub_heap_is_tainting()) {
  523. printf("******************************************"
  524. "*** Memory tainting is disabled so results\n"
  525. "*** of scan may miss some real leaks!\n"
  526. "******************************************\n\n");
  527. }
  528. lub_heap_scan_all();
  529. } else {
  530. printf("Leak detection currently disabled\n\n");
  531. }
  532. }
  533. /*--------------------------------------------------------- */
  534. bool_t lub_heap_leak_report(lub_heap_show_e how, const char *substring)
  535. {
  536. bool_t result = BOOL_FALSE;
  537. if (0 < lub_heap_frame_count) {
  538. bool_t bad_arg = BOOL_FALSE;
  539. lub_heap_leak_t *leak = lub_heap_leak_instance();
  540. context_show_arg_t show_arg;
  541. show_arg.how = how;
  542. show_arg.substring = substring;
  543. /* zero these stats which will be accumulated from the contexts */
  544. leak->m_stats.contexts = 0;
  545. leak->m_stats.allocs = 0;
  546. leak->m_stats.alloc_bytes = 0;
  547. leak->m_stats.alloc_overhead = 0;
  548. leak->m_stats.partials = 0;
  549. leak->m_stats.partial_bytes = 0;
  550. leak->m_stats.partial_overhead = 0;
  551. leak->m_stats.leaks = 0;
  552. leak->m_stats.leaked_bytes = 0;
  553. leak->m_stats.leaked_overhead = 0;
  554. lub_heap_leak_release(leak);
  555. switch (how) {
  556. case LUB_HEAP_SHOW_LEAKS:
  557. case LUB_HEAP_SHOW_PARTIALS:
  558. case LUB_HEAP_SHOW_ALL:
  559. {
  560. result =
  561. lub_heap_foreach_context
  562. (lub_heap_context_show_fn,
  563. (void *)&show_arg);
  564. break;
  565. }
  566. default:
  567. {
  568. printf
  569. ("Invalid argument: 0=leaks, 1=partials and leaks, 2=all allocations\n\n");
  570. bad_arg = BOOL_TRUE;
  571. break;
  572. }
  573. }
  574. if (BOOL_FALSE == bad_arg) {
  575. leak = lub_heap_leak_instance();
  576. if (leak->m_stats.leaks) {
  577. printf(" '*' = leaked memory\n");
  578. }
  579. if (leak->m_stats.partials) {
  580. printf(" '+' = partially leaked memory\n");
  581. }
  582. lub_heap_leak_release(leak);
  583. lub_heap_show_summary();
  584. printf
  585. (" %lu stack frames held for each allocation.\n\n",
  586. lub_heap_frame_count);
  587. }
  588. } else {
  589. printf("Leak detection currently disabled\n\n");
  590. }
  591. return result;
  592. }
  593. /*--------------------------------------------------------- */
  594. /*---------------------------------------------------------
  595. * PUBLIC META FUNCTIONS
  596. *--------------------------------------------------------- */
  597. void lub_heap__set_framecount(unsigned frames)
  598. {
  599. static bool_t clear_tainting_on_disable = BOOL_FALSE;
  600. lub_heap_leak_t *leak;
  601. if (frames == lub_heap_frame_count)
  602. return;
  603. /* iterate around clearing all the nodes in the node_tree */
  604. lub_heap_foreach_node(lub_heap_node_clear, 0);
  605. leak = lub_heap_leak_instance();
  606. if (frames) {
  607. static bool_t registered = BOOL_FALSE;
  608. if (frames <= MAX_BACKTRACE) {
  609. /* change the number of frames held */
  610. lub_heap_frame_count = frames;
  611. } else {
  612. fprintf(stderr,
  613. "--- leak-detection frame count set to a maximum of %d\n",
  614. MAX_BACKTRACE);
  615. lub_heap_frame_count = MAX_BACKTRACE;
  616. }
  617. if (!lub_heap_is_tainting()) {
  618. /* we need to taint memory to ensure old pointers don't mask leaks */
  619. clear_tainting_on_disable = BOOL_TRUE;
  620. lub_heap_taint(BOOL_TRUE);
  621. }
  622. if (BOOL_FALSE == registered) {
  623. registered = BOOL_TRUE;
  624. /*
  625. * set up the context pool
  626. */
  627. lub_dblockpool_init(&leak->m_context_pool,
  628. sizeof(lub_heap_context_t),
  629. CONTEXT_CHUNK_SIZE,
  630. CONTEXT_MAX_CHUNKS);
  631. }
  632. } else {
  633. /* switch off leak detection */
  634. lub_heap_frame_count = 0;
  635. if (clear_tainting_on_disable) {
  636. lub_heap_taint(BOOL_FALSE);
  637. clear_tainting_on_disable = BOOL_FALSE;
  638. }
  639. }
  640. lub_heap_leak_release(leak);
  641. }
  642. /*--------------------------------------------------------- */
  643. unsigned lub_heap__get_framecount(void)
  644. {
  645. return lub_heap_frame_count;
  646. }
  647. /*--------------------------------------------------------- */
  648. size_t lub_heap_context__get_instanceSize(void)
  649. {
  650. return (sizeof(lub_heap_context_t));
  651. }
  652. /*--------------------------------------------------------- */
  653. lub_heap_context_t *lub_heap_context_find(const stackframe_t * stack)
  654. {
  655. lub_heap_context_t *result;
  656. lub_heap_leak_t *leak = lub_heap_leak_instance();
  657. lub_heap_context_key_t key = *stack;
  658. result = lub_bintree_find(&leak->m_context_tree, &key);
  659. lub_heap_leak_release(leak);
  660. return result;
  661. }
  662. /*--------------------------------------------------------- */