aboutsummaryrefslogtreecommitdiffstats
path: root/epan/wmem
diff options
context:
space:
mode:
authorEvan Huus <eapache@gmail.com>2013-07-28 12:46:44 +0000
committerEvan Huus <eapache@gmail.com>2013-07-28 12:46:44 +0000
commitb43996c8abb7f75b2fcdb7a660ae7f9063cb4a10 (patch)
treeb558b201396c5c45bd7dc1e126b8b857093d3eb0 /epan/wmem
parent23d40bcfcf706e0a16bc08fa36503bf6ec64a965 (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.c30
-rw-r--r--epan/wmem/wmem_test.c10
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 */