123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- /*
- * node.c
- */
- #include <stdio.h>
- #include <string.h>
- #include <assert.h>
- #include "private.h"
- #include "context.h"
- #include "node.h"
- int lub_heap_leak_verbose = 0;
- /*--------------------------------------------------------- */
- int
- lub_heap_node_compare(const void *clientnode,
- const void *clientkey)
- {
- const lub_heap_node_t * node = clientnode;
- const lub_heap_node_key_t * key = clientkey;
-
- return ((long)node - (long)key->node);
- }
- /*--------------------------------------------------------- */
- /* we simply use the node address as the index */
- void
- lub_heap_node_getkey(const void *clientnode,
- lub_bintree_key_t *key)
- {
- lub_heap_node_key_t clientkey;
- clientkey.node = clientnode;
- memcpy(key,&clientkey,sizeof(lub_heap_node_key_t));
- }
- /*--------------------------------------------------------- */
- static void
- lub_heap_node_meta_init(void)
- {
- static bool_t initialised = BOOL_FALSE;
-
- if(BOOL_FALSE == initialised)
- {
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- initialised = BOOL_TRUE;
- /* initialise the node tree */
- lub_bintree_init(&leak->m_node_tree,
- offsetof(lub_heap_node_t,bt_node),
- lub_heap_node_compare,
- lub_heap_node_getkey);
- /* initialise the clear node tree */
- lub_bintree_init(&leak->m_clear_node_tree,
- offsetof(lub_heap_node_t,bt_node),
- lub_heap_node_compare,
- lub_heap_node_getkey);
- lub_heap_leak_release(leak);
- }
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node_init(lub_heap_node_t * this,
- lub_heap_context_t * context)
- {
- lub_heap_node_meta_init();
-
- /* initialise the control blocks */
- lub_bintree_node_init(&this->bt_node);
- lub_heap_node__set_context(this,context);
- lub_heap_node__set_leaked(this,BOOL_FALSE);
- lub_heap_node__set_partial(this,BOOL_FALSE);
- lub_heap_node__set_next(this,NULL);
- lub_heap_node__set_scanned(this,BOOL_FALSE);
- this->prev = NULL;
- {
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- /* add this to the node tree */
- lub_bintree_insert(context ? &leak->m_node_tree : &leak->m_clear_node_tree,this);
- lub_heap_leak_release(leak);
- }
- if(context)
- {
- /* add ourselves to this context */
- lub_heap_context_insert_node(context,this);
- /* maintain the leak statistics */
- ++context->allocs;
- context->alloc_bytes += lub_heap_node__get_size(this);
- context->alloc_overhead += lub_heap_node__get_overhead(this);
- }
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node_fini(lub_heap_node_t * this)
- {
- /* remove this node from this context */
- lub_heap_node_clear(this,0);
- {
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- /* remove this from the clear_node tree */
- lub_bintree_remove(&leak->m_clear_node_tree,this);
- lub_heap_leak_release(leak);
- }
- }
- /*--------------------------------------------------------- */
- size_t
- lub_heap_node__get_instanceSize(void)
- {
- return sizeof(lub_heap_node_t);
- }
- /*--------------------------------------------------------- */
- size_t
- lub_heap_node__get_size(const lub_heap_node_t *this)
- {
- size_t size = lub_heap__get_block_size(lub_heap_node__get_context(this)->heap,this);
- size -= sizeof(lub_heap_node_t);
- return size;
- }
- /*--------------------------------------------------------- */
- size_t
- lub_heap_node__get_overhead(const lub_heap_node_t *this)
- {
- size_t overhead;
-
- overhead = lub_heap__get_block_overhead(lub_heap_node__get_context(this)->heap,
- lub_heap_node__get_ptr(this));
-
- overhead += sizeof(lub_heap_node_t);
- return overhead;
- }
- /*--------------------------------------------------------- */
- char *
- lub_heap_node__get_ptr(const lub_heap_node_t *this)
- {
- return (char*)&this[1];
- }
- /*--------------------------------------------------------- */
- bool_t
- lub_heap_validate_pointer(lub_heap_t *this,
- char *ptr)
- {
- bool_t result = BOOL_FALSE;
- do
- {
- lub_heap_segment_t *seg;
- if((0 < lub_heap_frame_count))
- {
- /*
- * When leak detection is enabled we can perform detailed
- * validation of pointers.
- */
- lub_heap_node_t *node = lub_heap_node_from_start_of_block_ptr(ptr);
- if(NULL != node)
- {
- lub_heap_context_t *context = lub_heap_node__get_context(node);
- /* we've found a context so can give a definative answer */
- if(this == context->heap)
- {
- result = BOOL_TRUE;
- }
- break;
- }
- }
- /* iterate around each of the segments belonging to this heap */
- for(seg = &this->first_segment;
- seg;
- seg = seg->next)
- {
- char *start = (char*)&seg[1];
- if(ptr >= start)
- {
- char *end = start + (seg->words << 2);
- if(ptr < end)
- {
- /* we've found a parent segment for this pointer */
- result = BOOL_TRUE;
- break;
- }
- }
- }
- } while(0);
- ptr = 0; /* don't leave a pointer on the stack */
- return result;
- }
- /*--------------------------------------------------------- */
- static lub_heap_node_t *
- _lub_heap_node_from_ptr(lub_bintree_t *tree,
- const char *ptr,
- bool_t start_of_block)
- {
- lub_heap_node_t *result = 0;
- if(tree->root)
- {
- lub_heap_node_key_t key;
-
- /* search for the node which comes immediately before this pointer */
- key.node = (lub_heap_node_t *)ptr;
- result = lub_bintree_findprevious(tree,&key);
-
- if(NULL != result)
- {
- char *tmp = lub_heap_node__get_ptr(result);
- /* ensure that the pointer is within the scope of this node */
- if(start_of_block)
- {
- if(ptr != tmp)
- {
- /*
- * this should be an exact match and isn't
- */
- result = NULL;
- }
- }
- else if(ptr < tmp)
- {
- /*
- * this is referencing part of the node header
- */
- result = NULL;
- }
- else
- {
- /* compare with the end of the allocated memory */
- tmp += lub_heap_node__get_size(result);
- /* ensure that the pointer is within the scope of this node */
- if(ptr >= tmp)
- {
- /* out of range of this node */
- result = NULL;
- }
- }
- tmp = 0; /* don't leave a pointer on the stack */
- }
- }
- ptr = 0; /* don't leave a pointer on the stack */
- return result;
- }
- /*--------------------------------------------------------- */
- lub_heap_node_t *
- lub_heap_node_from_start_of_block_ptr(char *ptr)
- {
- lub_heap_node_t *result = 0;
- if(lub_heap_leak_query_node_tree())
- {
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- result = _lub_heap_node_from_ptr(&leak->m_node_tree,ptr,BOOL_TRUE);
- lub_heap_leak_release(leak);
- }
- if((0 == result) && lub_heap_leak_query_clear_node_tree())
- {
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- result = _lub_heap_node_from_ptr(&leak->m_clear_node_tree,ptr,BOOL_TRUE);
- lub_heap_leak_release(leak);
- }
- ptr = 0; /* don't leave a pointer on the stack */
- return result;
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node__set_context(lub_heap_node_t *this,
- lub_heap_context_t *value)
- {
- unsigned long mask = ((unsigned long)value & ~(LEAKED_MASK | PARTIAL_MASK));
- this->_context = (lub_heap_context_t *)mask;
- }
- /*--------------------------------------------------------- */
- lub_heap_context_t *
- lub_heap_node__get_context(const lub_heap_node_t *this)
- {
- unsigned long mask = (unsigned long)this->_context & ~(LEAKED_MASK | PARTIAL_MASK);
- return (lub_heap_context_t *)mask;
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node__set_next(lub_heap_node_t *this,
- lub_heap_node_t *value)
- {
- unsigned long mask = ((unsigned long)value & ~(SCANNED_MASK));
- this->_next = (lub_heap_node_t *)mask;
- }
- /*--------------------------------------------------------- */
- lub_heap_node_t *
- lub_heap_node__get_next(const lub_heap_node_t *this)
- {
- unsigned long mask = (unsigned long)this->_next & ~(SCANNED_MASK);
- return (lub_heap_node_t *)mask;
- }
- /*--------------------------------------------------------- */
- bool_t
- lub_heap_node__get_leaked(const lub_heap_node_t *this)
- {
- return ((unsigned long)this->_context & LEAKED_MASK) ? BOOL_TRUE : BOOL_FALSE;
- }
- /*--------------------------------------------------------- */
- bool_t
- lub_heap_node__get_partial(const lub_heap_node_t *this)
- {
- return ((unsigned long)this->_context & PARTIAL_MASK) ? BOOL_TRUE : BOOL_FALSE;
- }
- /*--------------------------------------------------------- */
- bool_t
- lub_heap_node__get_scanned(const lub_heap_node_t *this)
- {
- return ((unsigned long)this->_next & SCANNED_MASK) ? BOOL_TRUE : BOOL_FALSE;
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node__set_leaked(lub_heap_node_t *this, bool_t value)
- {
- unsigned long mask = (unsigned long)this->_context;
- if(BOOL_TRUE == value)
- {
- mask |= LEAKED_MASK;
- }
- else
- {
- mask &= ~LEAKED_MASK;
- }
- this->_context = (lub_heap_context_t *)mask;
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node__set_partial(lub_heap_node_t *this, bool_t value)
- {
- unsigned long mask = (unsigned long)this->_context;
- if(BOOL_TRUE == value)
- {
- mask |= PARTIAL_MASK;
- }
- else
- {
- mask &= ~PARTIAL_MASK;
- }
- this->_context = (lub_heap_context_t *)mask;
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node__set_scanned(lub_heap_node_t *this, bool_t value)
- {
- unsigned long mask = (unsigned long)this->_next;
- if(BOOL_TRUE == value)
- {
- mask |= SCANNED_MASK;
- }
- else
- {
- mask &= ~SCANNED_MASK;
- }
- this->_next = (lub_heap_node_t *)mask;
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_foreach_node(void (*fn)(lub_heap_node_t *,void*),
- void *arg)
- {
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- lub_heap_node_t *node;
- lub_heap_node_key_t key;
- for(node = lub_bintree_findfirst(&leak->m_node_tree);
- node;
- node = lub_bintree_findnext(&leak->m_node_tree,&key))
- {
- lub_heap_leak_release(leak);
- lub_heap_node_getkey(node,(lub_bintree_key_t*)&key);
- /* invoke the specified method on this node */
- fn(node,arg);
- leak = lub_heap_leak_instance();
- }
- lub_heap_leak_release(leak);
- }
- /*--------------------------------------------------------- */
- void
- lub_heap_node_clear(lub_heap_node_t *this,
- void *arg)
- {
- /* clearing a node removes it from it's context */
- lub_heap_context_t *context = lub_heap_node__get_context(this);
- if(NULL != context)
- {
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- /* remove from the node tree and place into the clear tree */
- lub_bintree_remove(&leak->m_node_tree,this);
- lub_bintree_insert(&leak->m_clear_node_tree,this);
- lub_heap_leak_release(leak);
- /* maintain the leak statistics */
- --context->allocs;
- context->alloc_bytes -= lub_heap_node__get_size(this);
- context->alloc_overhead -= lub_heap_node__get_overhead(this);
- lub_heap_node__set_context(this,NULL);
- lub_heap_node__set_leaked(this,BOOL_FALSE);
- lub_heap_node__set_partial(this,BOOL_FALSE);
- lub_heap_context_remove_node(context,this);
- }
- }
- /*--------------------------------------------------------- */
- #define RELEASE_COUNT 2048
- void
- lub_heap_scan_memory(const void *mem,
- size_t size)
- {
- size_t bytes_left = size;
- typedef const void *void_ptr;
- void_ptr *ptr,last_ptr = 0;
- lub_heap_leak_t *leak = lub_heap_leak_instance();
- unsigned release_count = RELEASE_COUNT;
- if(lub_heap_leak_verbose)
- {
- printf("lub_heap_scan_memory(%p,%"SIZE_FMT")\n",mem,size);
- }
- ++leak->m_stats.scanned;
-
- /* scan all the words in this allocated block of memory */
- for(ptr = (void_ptr*)mem;
- bytes_left;
- )
- {
- if(0 == --release_count)
- {
- /* make space for other memory tasks to get in... */
- lub_heap_leak_release(leak);
- leak = lub_heap_leak_instance();
- release_count = RELEASE_COUNT;
- }
- if(*ptr != last_ptr)
- {
- lub_heap_node_t *node;
- lub_heap_node_key_t key;
-
- /* search for a node */
- key.node = (lub_heap_node_t *)ptr;
- node = lub_bintree_find(&leak->m_node_tree,&key);
- if(NULL != node)
- {
- /*
- * If we stumble across a node don't scan it's contents as this could cause
- * false negatives. This situation could occur if an allocated block of memory
- * was used as a heap in it's own right.
- */
- char *tmp = lub_heap_node__get_ptr(node);
- size_t node_size = lub_heap_node__get_size(node);
-
- /* skip forward past the node contents */
- ptr = (void_ptr*)(tmp + node_size);
- bytes_left -= (node_size + sizeof(lub_heap_node_t));
- tmp = 0; /* don't leave pointers on our stack */
- last_ptr = 0;
- continue;
- }
- /*
- * see whether this is a reference to a node
- * NB. we only resolve a node if the pointer lies
- * within the memory allocated to the client; any direct
- * references to nodes will not resolve to a node
- * object.
- */
- node = _lub_heap_node_from_ptr(&leak->m_node_tree,*ptr,BOOL_FALSE);
- if( (NULL != node))
- {
- /* this looks like a valid node */
- lub_heap_context_t *context = lub_heap_node__get_context(node);
- size_t node_size = lub_heap_node__get_size(node);
- size_t node_overhead = lub_heap_node__get_overhead(node);
- char *tmp = lub_heap_node__get_ptr(node);
- if(tmp == *ptr)
- {
- /* reference to start of block */
- if(BOOL_TRUE == lub_heap_node__get_partial(node))
- {
- lub_heap_node__set_partial(node,BOOL_FALSE);
-
- if(NULL != context)
- {
- --context->partials;
- context->partial_bytes -= node_size;
- context->partial_overhead -= node_overhead;
- }
- }
- }
- tmp = 0; /* don't leave pointers on our stack */
- /* this is definately not a leak */
- if(BOOL_TRUE == lub_heap_node__get_leaked(node))
- {
- lub_heap_node__set_leaked(node,BOOL_FALSE);
-
- if(NULL != context)
- {
- --context->leaks;
- context->leaked_bytes -= node_size;
- context->leaked_overhead -= node_overhead;
-
- --leak->m_stats.leaks;
- leak->m_stats.leaked_bytes -= node_size;
- leak->m_stats.leaked_overhead -= node_overhead;
- }
- }
- }
- }
- last_ptr = *ptr++;
- bytes_left -= sizeof(void*);
- }
- lub_heap_leak_release(leak);
- last_ptr = ptr = 0; /* don't leave pointers on the stack */
- }
- /*--------------------------------------------------------- */
|