[PATCH] dkhash: memory leak and possible loss of objects in dkhash_remove

Andreas Ericsson ae at op5.se
Wed Feb 20 19:03:39 CET 2013


Nice catch. I'll remove the unrelated changes and apply.

Thanks.

On 02/20/2013 05:48 PM, max.sikstrom at op5.com wrote:
> From: Max Sikström <msikstrom at op5.com>
> 
> Pointer to previous in dkhash_remove was only set for first element in a given
> bucket. So when finding for example third object for removal, setting
> prev->next=obj->next looses the reference to the old prev->next, which is the
> second object in the list.
> 
> This can be tested by creating a hash map of one bucket (practically a linked
> list), and fill and remove all, both forward and backward.
> 
> Signed-off-by: Max Sikström <msikstrom at op5.com>
> ---
>   lib/dkhash.c      |    5 ++---
>   lib/test-dkhash.c |   36 +++++++++++++++++++++++++++++++++++-
>   2 files changed, 37 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/dkhash.c b/lib/dkhash.c
> index cab3d66..74a9a76 100644
> --- a/lib/dkhash.c
> +++ b/lib/dkhash.c
> @@ -209,9 +209,7 @@ void *dkhash_remove(dkhash_table *t, const char *k1, const char *k2)
>   
>   	prev = bkt; /* pay attention */
>   	for (; bkt; bkt = bkt->next) {
> -		if (strcmp(k1, bkt->key))
> -			continue;
> -		if ((!k2 && !bkt->key2) || !strcmp(k2, bkt->key2)) {
> +		if (!strcmp(k1, bkt->key) && ((!k2 && !bkt->key2) || !strcmp(k2, bkt->key2)) ) {
>   			if (prev == bkt) {
>   				/* first entry deleted */
>   				t->buckets[slot] = bkt->next;
> @@ -223,6 +221,7 @@ void *dkhash_remove(dkhash_table *t, const char *k1, const char *k2)
>   			t->removed++;
>   			return dkhash_destroy_bucket(bkt);
>   		}
> +		prev = bkt;
>   	}
>   
>   	return NULL;
> diff --git a/lib/test-dkhash.c b/lib/test-dkhash.c
> index 02accba..313b361 100644
> --- a/lib/test-dkhash.c
> +++ b/lib/test-dkhash.c
> @@ -87,10 +87,13 @@ static int del_matching(void *data)
>   int main(int argc, char **argv)
>   {
>   	dkhash_table *tx, *t;
> -	unsigned int x;
> +	int x;
>   	struct test_data s;
>   	char *p1, *p2;
>   
> +	char *strs[10];
> +	char tmp[32];
> +
>   	t_set_colors(0);
>   	t_start("dkhash basic test");
>   	t = dkhash_create(512);
> @@ -143,6 +146,37 @@ int main(int argc, char **argv)
>   	test(0 == dkhash_num_entries(tx), "x table post all ops");
>   	test(0 == dkhash_check_table(tx), "x table consistency post all ops");
>   	dkhash_debug_table(tx, 0);
> +	t_end();
> +
> +	for(x=0;x<10;x++) {
> +		sprintf(tmp, "string %d", x);
> +		strs[x] = strdup(tmp);
> +	}
> +
> +	t_start("dkhash single bucket add remove forward");
> +
> +	t = dkhash_create(1);
> +	for(x=0;x<10;x++) {
> +		dkhash_insert( t, strs[x], NULL, strs[x] );
> +	}
> +	for(x=0;x<10;x++) {
> +		p1 = strs[x];
> +		p2 = dkhash_remove( t, p1, NULL );
> +		test( p1 == p2, "remove should return a value" );
> +	}
> +	t_end();
> +
> +	t_start("dkhash single bucket add remove backward");
> +
> +	t = dkhash_create(1);
> +	for(x=0;x<10;x++) {
> +		dkhash_insert( t, strs[x], NULL, strs[x] );
> +	}
> +	for(x=9;x>=0;x--) {
> +		p1 = strs[x];
> +		p2 = dkhash_remove( t, p1, NULL );
> +		test( p1 == p2, "remove should return a value" );
> +	}
>   
>   	return t_end();
>   }
> 


-- 
Andreas Ericsson                   andreas.ericsson at op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

Considering the successes of the wars on alcohol, poverty, drugs and
terror, I think we should give some serious thought to declaring war
on peace.

------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_feb




More information about the Developers mailing list