diff options
author | Evan Huus <eapache@gmail.com> | 2013-07-28 12:46:44 +0000 |
---|---|---|
committer | Evan Huus <eapache@gmail.com> | 2013-07-28 12:46:44 +0000 |
commit | b43996c8abb7f75b2fcdb7a660ae7f9063cb4a10 (patch) | |
tree | b558b201396c5c45bd7dc1e126b8b857093d3eb0 /epan/wmem | |
parent | 23d40bcfcf706e0a16bc08fa36503bf6ec64a965 (diff) |
Fix a bug in the gc routine discovered while formally working out parts of the
algorithm.
Also add a test case to excercise it for future.
svn path=/trunk/; revision=50970
Diffstat (limited to 'epan/wmem')
-rw-r--r-- | epan/wmem/wmem_allocator_block.c | 30 | ||||
-rw-r--r-- | epan/wmem/wmem_test.c | 10 |
2 files changed, 29 insertions, 11 deletions
diff --git a/epan/wmem/wmem_allocator_block.c b/epan/wmem/wmem_allocator_block.c index 37591d8fed..f343af9fa3 100644 --- a/epan/wmem/wmem_allocator_block.c +++ b/epan/wmem/wmem_allocator_block.c @@ -885,6 +885,7 @@ wmem_block_gc(void *private_data) wmem_block_allocator_t *allocator = (wmem_block_allocator_t*) private_data; GSList *tmp, *new_block_list = NULL; wmem_block_chunk_t *chunk; + wmem_block_free_t *free_chunk; /* Walk through the blocks, adding used blocks to a new list and * completely destroying unused blocks. The newly built list is the new @@ -897,10 +898,24 @@ wmem_block_gc(void *private_data) if (!chunk->used && chunk->last) { /* If the first chunk is also the last, and is unused, then * the block as a whole is entirely unused, so return it to - * the OS. If it is also the head of the master list then set that - * to NULL since all of its blocks are about to be removed. */ - if (chunk == allocator->master_head) { - allocator->master_head = NULL; + * the OS and remove it from whatever lists it is in. */ + free_chunk = WMEM_GET_FREE(chunk); + if (free_chunk->next) { + WMEM_GET_FREE(free_chunk->next)->prev = free_chunk->prev; + } + if (free_chunk->prev) { + WMEM_GET_FREE(free_chunk->prev)->next = free_chunk->next; + } + if (allocator->recycler_head == chunk) { + if (free_chunk->next == chunk) { + allocator->recycler_head = NULL; + } + else { + allocator->recycler_head = free_chunk->next; + } + } + else if (allocator->master_head == chunk) { + allocator->master_head = free_chunk->next; } g_free(chunk); } @@ -916,13 +931,6 @@ wmem_block_gc(void *private_data) g_slist_free(allocator->block_list); /* and store the new list */ allocator->block_list = new_block_list; - - /* If master_head is still non-NULL then only the head element remains valid - * (all the others have been removed by now) so truncate the list to just - * one element. */ - if (allocator->master_head) { - WMEM_GET_FREE(allocator->master_head)->next = NULL; - } } static void diff --git a/epan/wmem/wmem_test.c b/epan/wmem/wmem_test.c index c4a999a5af..eb23b9dcfa 100644 --- a/epan/wmem/wmem_test.c +++ b/epan/wmem/wmem_test.c @@ -256,6 +256,16 @@ wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify) wmem_gc(allocator); if (verify) (*verify)(allocator); + ptrs[0] = (char*)wmem_alloc0(allocator, 4*1024*1024); + wmem_free(allocator, ptrs[0]); + wmem_gc(allocator); + ptrs[0] = (char*)wmem_alloc0(allocator, 4*1024*1024); + + if (verify) (*verify)(allocator); + wmem_free_all(allocator); + wmem_gc(allocator); + if (verify) (*verify)(allocator); + /* now do some random fuzz-like tests */ /* reset our ptr array */ |