node.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /*
  2. * node.c
  3. */
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <assert.h>
  7. #include "private.h"
  8. #include "context.h"
  9. #include "node.h"
  10. int lub_heap_leak_verbose = 0;
  11. /*--------------------------------------------------------- */
  12. int lub_heap_node_compare(const void *clientnode, const void *clientkey)
  13. {
  14. const lub_heap_node_t *node = clientnode;
  15. const lub_heap_node_key_t *key = clientkey;
  16. return ((long)node - (long)key->node);
  17. }
  18. /*--------------------------------------------------------- */
  19. /* we simply use the node address as the index */
  20. void lub_heap_node_getkey(const void *clientnode, lub_bintree_key_t * key)
  21. {
  22. lub_heap_node_key_t clientkey;
  23. clientkey.node = clientnode;
  24. memcpy(key, &clientkey, sizeof(lub_heap_node_key_t));
  25. }
  26. /*--------------------------------------------------------- */
  27. static void lub_heap_node_meta_init(void)
  28. {
  29. static bool_t initialised = BOOL_FALSE;
  30. if (BOOL_FALSE == initialised) {
  31. lub_heap_leak_t *leak = lub_heap_leak_instance();
  32. initialised = BOOL_TRUE;
  33. /* initialise the node tree */
  34. lub_bintree_init(&leak->m_node_tree,
  35. offsetof(lub_heap_node_t, bt_node),
  36. lub_heap_node_compare, lub_heap_node_getkey);
  37. /* initialise the clear node tree */
  38. lub_bintree_init(&leak->m_clear_node_tree,
  39. offsetof(lub_heap_node_t, bt_node),
  40. lub_heap_node_compare, lub_heap_node_getkey);
  41. lub_heap_leak_release(leak);
  42. }
  43. }
  44. /*--------------------------------------------------------- */
  45. void lub_heap_node_init(lub_heap_node_t * this, lub_heap_context_t * context)
  46. {
  47. lub_heap_node_meta_init();
  48. /* initialise the control blocks */
  49. lub_bintree_node_init(&this->bt_node);
  50. lub_heap_node__set_context(this, context);
  51. lub_heap_node__set_leaked(this, BOOL_FALSE);
  52. lub_heap_node__set_partial(this, BOOL_FALSE);
  53. lub_heap_node__set_next(this, NULL);
  54. lub_heap_node__set_scanned(this, BOOL_FALSE);
  55. this->prev = NULL;
  56. {
  57. lub_heap_leak_t *leak = lub_heap_leak_instance();
  58. /* add this to the node tree */
  59. lub_bintree_insert(context ? &leak->m_node_tree : &leak->
  60. m_clear_node_tree, this);
  61. lub_heap_leak_release(leak);
  62. }
  63. if (context) {
  64. /* add ourselves to this context */
  65. lub_heap_context_insert_node(context, this);
  66. /* maintain the leak statistics */
  67. ++context->allocs;
  68. context->alloc_bytes += lub_heap_node__get_size(this);
  69. context->alloc_overhead += lub_heap_node__get_overhead(this);
  70. }
  71. }
  72. /*--------------------------------------------------------- */
  73. void lub_heap_node_fini(lub_heap_node_t * this)
  74. {
  75. /* remove this node from this context */
  76. lub_heap_node_clear(this, 0);
  77. {
  78. lub_heap_leak_t *leak = lub_heap_leak_instance();
  79. /* remove this from the clear_node tree */
  80. lub_bintree_remove(&leak->m_clear_node_tree, this);
  81. lub_heap_leak_release(leak);
  82. }
  83. }
  84. /*--------------------------------------------------------- */
  85. size_t lub_heap_node__get_instanceSize(void)
  86. {
  87. return sizeof(lub_heap_node_t);
  88. }
  89. /*--------------------------------------------------------- */
  90. size_t lub_heap_node__get_size(const lub_heap_node_t * this)
  91. {
  92. size_t size =
  93. lub_heap__get_block_size(lub_heap_node__get_context(this)->heap,
  94. this);
  95. size -= sizeof(lub_heap_node_t);
  96. return size;
  97. }
  98. /*--------------------------------------------------------- */
  99. size_t lub_heap_node__get_overhead(const lub_heap_node_t * this)
  100. {
  101. size_t overhead;
  102. overhead =
  103. lub_heap__get_block_overhead(lub_heap_node__get_context(this)->heap,
  104. lub_heap_node__get_ptr(this));
  105. overhead += sizeof(lub_heap_node_t);
  106. return overhead;
  107. }
  108. /*--------------------------------------------------------- */
  109. char *lub_heap_node__get_ptr(const lub_heap_node_t * this)
  110. {
  111. return (char *)&this[1];
  112. }
  113. /*--------------------------------------------------------- */
  114. bool_t lub_heap_validate_pointer(lub_heap_t * this, char *ptr)
  115. {
  116. bool_t result = BOOL_FALSE;
  117. do {
  118. lub_heap_segment_t *seg;
  119. if ((0 < lub_heap_frame_count)) {
  120. /*
  121. * When leak detection is enabled we can perform detailed
  122. * validation of pointers.
  123. */
  124. lub_heap_node_t *node =
  125. lub_heap_node_from_start_of_block_ptr(ptr);
  126. if (NULL != node) {
  127. lub_heap_context_t *context =
  128. lub_heap_node__get_context(node);
  129. /* we've found a context so can give a definative answer */
  130. if (this == context->heap) {
  131. result = BOOL_TRUE;
  132. }
  133. break;
  134. }
  135. }
  136. /* iterate around each of the segments belonging to this heap */
  137. for (seg = &this->first_segment; seg; seg = seg->next) {
  138. char *start = (char *)&seg[1];
  139. if (ptr >= start) {
  140. char *end = start + (seg->words << 2);
  141. if (ptr < end) {
  142. /* we've found a parent segment for this pointer */
  143. result = BOOL_TRUE;
  144. break;
  145. }
  146. }
  147. }
  148. } while (0);
  149. ptr = 0; /* don't leave a pointer on the stack */
  150. return result;
  151. }
  152. /*--------------------------------------------------------- */
  153. static lub_heap_node_t *_lub_heap_node_from_ptr(lub_bintree_t * tree,
  154. const char *ptr,
  155. bool_t start_of_block)
  156. {
  157. lub_heap_node_t *result = 0;
  158. if (tree->root) {
  159. lub_heap_node_key_t key;
  160. /* search for the node which comes immediately before this pointer */
  161. key.node = (lub_heap_node_t *) ptr;
  162. result = lub_bintree_findprevious(tree, &key);
  163. if (NULL != result) {
  164. char *tmp = lub_heap_node__get_ptr(result);
  165. /* ensure that the pointer is within the scope of this node */
  166. if (start_of_block) {
  167. if (ptr != tmp) {
  168. /*
  169. * this should be an exact match and isn't
  170. */
  171. result = NULL;
  172. }
  173. } else if (ptr < tmp) {
  174. /*
  175. * this is referencing part of the node header
  176. */
  177. result = NULL;
  178. } else {
  179. /* compare with the end of the allocated memory */
  180. tmp += lub_heap_node__get_size(result);
  181. /* ensure that the pointer is within the scope of this node */
  182. if (ptr >= tmp) {
  183. /* out of range of this node */
  184. result = NULL;
  185. }
  186. }
  187. tmp = 0; /* don't leave a pointer on the stack */
  188. }
  189. }
  190. ptr = 0; /* don't leave a pointer on the stack */
  191. return result;
  192. }
  193. /*--------------------------------------------------------- */
  194. lub_heap_node_t *lub_heap_node_from_start_of_block_ptr(char *ptr)
  195. {
  196. lub_heap_node_t *result = 0;
  197. if (lub_heap_leak_query_node_tree()) {
  198. lub_heap_leak_t *leak = lub_heap_leak_instance();
  199. result =
  200. _lub_heap_node_from_ptr(&leak->m_node_tree, ptr, BOOL_TRUE);
  201. lub_heap_leak_release(leak);
  202. }
  203. if ((0 == result) && lub_heap_leak_query_clear_node_tree()) {
  204. lub_heap_leak_t *leak = lub_heap_leak_instance();
  205. result =
  206. _lub_heap_node_from_ptr(&leak->m_clear_node_tree, ptr,
  207. BOOL_TRUE);
  208. lub_heap_leak_release(leak);
  209. }
  210. ptr = 0; /* don't leave a pointer on the stack */
  211. return result;
  212. }
  213. /*--------------------------------------------------------- */
  214. void
  215. lub_heap_node__set_context(lub_heap_node_t * this, lub_heap_context_t * value)
  216. {
  217. unsigned long mask =
  218. ((unsigned long)value & ~(LEAKED_MASK | PARTIAL_MASK));
  219. this->_context = (lub_heap_context_t *) mask;
  220. }
  221. /*--------------------------------------------------------- */
  222. lub_heap_context_t *lub_heap_node__get_context(const lub_heap_node_t * this)
  223. {
  224. unsigned long mask =
  225. (unsigned long)this->_context & ~(LEAKED_MASK | PARTIAL_MASK);
  226. return (lub_heap_context_t *) mask;
  227. }
  228. /*--------------------------------------------------------- */
  229. void lub_heap_node__set_next(lub_heap_node_t * this, lub_heap_node_t * value)
  230. {
  231. unsigned long mask = ((unsigned long)value & ~(SCANNED_MASK));
  232. this->_next = (lub_heap_node_t *) mask;
  233. }
  234. /*--------------------------------------------------------- */
  235. lub_heap_node_t *lub_heap_node__get_next(const lub_heap_node_t * this)
  236. {
  237. unsigned long mask = (unsigned long)this->_next & ~(SCANNED_MASK);
  238. return (lub_heap_node_t *) mask;
  239. }
  240. /*--------------------------------------------------------- */
  241. bool_t lub_heap_node__get_leaked(const lub_heap_node_t * this)
  242. {
  243. return ((unsigned long)this->
  244. _context & LEAKED_MASK) ? BOOL_TRUE : BOOL_FALSE;
  245. }
  246. /*--------------------------------------------------------- */
  247. bool_t lub_heap_node__get_partial(const lub_heap_node_t * this)
  248. {
  249. return ((unsigned long)this->
  250. _context & PARTIAL_MASK) ? BOOL_TRUE : BOOL_FALSE;
  251. }
  252. /*--------------------------------------------------------- */
  253. bool_t lub_heap_node__get_scanned(const lub_heap_node_t * this)
  254. {
  255. return ((unsigned long)this->
  256. _next & SCANNED_MASK) ? BOOL_TRUE : BOOL_FALSE;
  257. }
  258. /*--------------------------------------------------------- */
  259. void lub_heap_node__set_leaked(lub_heap_node_t * this, bool_t value)
  260. {
  261. unsigned long mask = (unsigned long)this->_context;
  262. if (BOOL_TRUE == value) {
  263. mask |= LEAKED_MASK;
  264. } else {
  265. mask &= ~LEAKED_MASK;
  266. }
  267. this->_context = (lub_heap_context_t *) mask;
  268. }
  269. /*--------------------------------------------------------- */
  270. void lub_heap_node__set_partial(lub_heap_node_t * this, bool_t value)
  271. {
  272. unsigned long mask = (unsigned long)this->_context;
  273. if (BOOL_TRUE == value) {
  274. mask |= PARTIAL_MASK;
  275. } else {
  276. mask &= ~PARTIAL_MASK;
  277. }
  278. this->_context = (lub_heap_context_t *) mask;
  279. }
  280. /*--------------------------------------------------------- */
  281. void lub_heap_node__set_scanned(lub_heap_node_t * this, bool_t value)
  282. {
  283. unsigned long mask = (unsigned long)this->_next;
  284. if (BOOL_TRUE == value) {
  285. mask |= SCANNED_MASK;
  286. } else {
  287. mask &= ~SCANNED_MASK;
  288. }
  289. this->_next = (lub_heap_node_t *) mask;
  290. }
  291. /*--------------------------------------------------------- */
  292. void lub_heap_foreach_node(void (*fn) (lub_heap_node_t *, void *), void *arg)
  293. {
  294. lub_heap_leak_t *leak = lub_heap_leak_instance();
  295. lub_heap_node_t *node;
  296. lub_heap_node_key_t key;
  297. for (node = lub_bintree_findfirst(&leak->m_node_tree);
  298. node; node = lub_bintree_findnext(&leak->m_node_tree, &key)) {
  299. lub_heap_leak_release(leak);
  300. lub_heap_node_getkey(node, (lub_bintree_key_t *) & key);
  301. /* invoke the specified method on this node */
  302. fn(node, arg);
  303. leak = lub_heap_leak_instance();
  304. }
  305. lub_heap_leak_release(leak);
  306. }
  307. /*--------------------------------------------------------- */
  308. void lub_heap_node_clear(lub_heap_node_t * this, void *arg)
  309. {
  310. /* clearing a node removes it from it's context */
  311. lub_heap_context_t *context = lub_heap_node__get_context(this);
  312. if (NULL != context) {
  313. lub_heap_leak_t *leak = lub_heap_leak_instance();
  314. /* remove from the node tree and place into the clear tree */
  315. lub_bintree_remove(&leak->m_node_tree, this);
  316. lub_bintree_insert(&leak->m_clear_node_tree, this);
  317. lub_heap_leak_release(leak);
  318. /* maintain the leak statistics */
  319. --context->allocs;
  320. context->alloc_bytes -= lub_heap_node__get_size(this);
  321. context->alloc_overhead -= lub_heap_node__get_overhead(this);
  322. lub_heap_node__set_context(this, NULL);
  323. lub_heap_node__set_leaked(this, BOOL_FALSE);
  324. lub_heap_node__set_partial(this, BOOL_FALSE);
  325. lub_heap_context_remove_node(context, this);
  326. }
  327. }
  328. /*--------------------------------------------------------- */
  329. #define RELEASE_COUNT 2048
  330. void lub_heap_scan_memory(const void *mem, size_t size)
  331. {
  332. size_t bytes_left = size;
  333. typedef const void *void_ptr;
  334. void_ptr *ptr, last_ptr = 0;
  335. lub_heap_leak_t *leak = lub_heap_leak_instance();
  336. unsigned release_count = RELEASE_COUNT;
  337. if (lub_heap_leak_verbose) {
  338. printf("lub_heap_scan_memory(%p,%" SIZE_FMT ")\n", mem, size);
  339. }
  340. ++leak->m_stats.scanned;
  341. /* scan all the words in this allocated block of memory */
  342. for (ptr = (void_ptr *) mem; bytes_left;) {
  343. if (0 == --release_count) {
  344. /* make space for other memory tasks to get in... */
  345. lub_heap_leak_release(leak);
  346. leak = lub_heap_leak_instance();
  347. release_count = RELEASE_COUNT;
  348. }
  349. if (*ptr != last_ptr) {
  350. lub_heap_node_t *node;
  351. lub_heap_node_key_t key;
  352. /* search for a node */
  353. key.node = (lub_heap_node_t *) ptr;
  354. node = lub_bintree_find(&leak->m_node_tree, &key);
  355. if (NULL != node) {
  356. /*
  357. * If we stumble across a node don't scan it's contents as this could cause
  358. * false negatives. This situation could occur if an allocated block of memory
  359. * was used as a heap in it's own right.
  360. */
  361. char *tmp = lub_heap_node__get_ptr(node);
  362. size_t node_size =
  363. lub_heap_node__get_size(node);
  364. /* skip forward past the node contents */
  365. ptr = (void_ptr *) (tmp + node_size);
  366. bytes_left -=
  367. (node_size + sizeof(lub_heap_node_t));
  368. tmp = 0; /* don't leave pointers on our stack */
  369. last_ptr = 0;
  370. continue;
  371. }
  372. /*
  373. * see whether this is a reference to a node
  374. * NB. we only resolve a node if the pointer lies
  375. * within the memory allocated to the client; any direct
  376. * references to nodes will not resolve to a node
  377. * object.
  378. */
  379. node =
  380. _lub_heap_node_from_ptr(&leak->m_node_tree, *ptr,
  381. BOOL_FALSE);
  382. if ((NULL != node)) {
  383. /* this looks like a valid node */
  384. lub_heap_context_t *context =
  385. lub_heap_node__get_context(node);
  386. size_t node_size =
  387. lub_heap_node__get_size(node);
  388. size_t node_overhead =
  389. lub_heap_node__get_overhead(node);
  390. char *tmp = lub_heap_node__get_ptr(node);
  391. if (tmp == *ptr) {
  392. /* reference to start of block */
  393. if (BOOL_TRUE ==
  394. lub_heap_node__get_partial(node)) {
  395. lub_heap_node__set_partial(node,
  396. BOOL_FALSE);
  397. if (NULL != context) {
  398. --context->partials;
  399. context->
  400. partial_bytes -=
  401. node_size;
  402. context->
  403. partial_overhead -=
  404. node_overhead;
  405. }
  406. }
  407. }
  408. tmp = 0; /* don't leave pointers on our stack */
  409. /* this is definately not a leak */
  410. if (BOOL_TRUE ==
  411. lub_heap_node__get_leaked(node)) {
  412. lub_heap_node__set_leaked(node,
  413. BOOL_FALSE);
  414. if (NULL != context) {
  415. --context->leaks;
  416. context->leaked_bytes -=
  417. node_size;
  418. context->leaked_overhead -=
  419. node_overhead;
  420. --leak->m_stats.leaks;
  421. leak->m_stats.leaked_bytes -=
  422. node_size;
  423. leak->m_stats.leaked_overhead -=
  424. node_overhead;
  425. }
  426. }
  427. }
  428. }
  429. last_ptr = *ptr++;
  430. bytes_left -= sizeof(void *);
  431. }
  432. lub_heap_leak_release(leak);
  433. last_ptr = ptr = 0; /* don't leave pointers on the stack */
  434. }
  435. /*--------------------------------------------------------- */