From af8d28014f97ab0d9e4d00961e72aefd7adb470b Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw@gnome.org>
Date: Tue, 27 Mar 2012 12:14:56 +0200
Subject: [PATCH 1/6] Fix broken hashmap behavior

 * We were relying on undefined gcc behavior related to the &
   operator.
 * This would show up as a test failure when running with -O2 on
   certain GCC versions, as well as failure on clang 3.1
---
 p11-kit/hashmap.c |   12 +++++-------
 tests/hash-test.c |    2 --
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/p11-kit/hashmap.c b/p11-kit/hashmap.c
index ceb8a17..1c4aff1 100644
--- a/p11-kit/hashmap.c
+++ b/p11-kit/hashmap.c
@@ -64,7 +64,7 @@ next_entry (hashiter *iter)
 {
 	hashbucket *bucket = iter->next;
 	while (!bucket) {
-		if (iter->index > iter->map->num_buckets)
+		if (iter->index >= iter->map->num_buckets)
 			return NULL;
 		bucket = iter->map->buckets[iter->index++];
 	}
@@ -109,7 +109,7 @@ lookup_or_create_bucket (hashmap *map,
 	hash = map->hash_func (key);
 
 	/* scan linked list */
-	for (bucketp = &map->buckets[map->num_buckets & hash];
+	for (bucketp = &map->buckets[hash % map->num_buckets];
 	     *bucketp != NULL; bucketp = &(*bucketp)->next) {
 		if((*bucketp)->hashed == hash && map->equal_func ((*bucketp)->key, key))
 			break;
@@ -167,14 +167,13 @@ _p11_hash_set (hashmap *map,
 		/* check that the collision rate isn't too high */
 		if (map->num_items > map->num_buckets) {
 			num_buckets = map->num_buckets * 2 + 1;
-			new_buckets = (hashbucket **)calloc (sizeof (hashbucket *),
-			                                     num_buckets + 1);
+			new_buckets = (hashbucket **)calloc (sizeof (hashbucket *), num_buckets);
 
 			/* Ignore failures, maybe we can expand later */
 			if(new_buckets) {
 				_p11_hash_iterate (map, &iter);
 				while ((bucket = next_entry (&iter)) != NULL) {
-					unsigned int i = bucket->hashed & num_buckets;
+					unsigned int i = bucket->hashed % num_buckets;
 					bucket->next = new_buckets[i];
 					new_buckets[i] = bucket;
 				}
@@ -276,8 +275,7 @@ _p11_hash_create (hash_hash_func hash_func,
 		map->value_destroy_func = value_destroy_func;
 
 		map->num_buckets = 9;
-		map->buckets = (hashbucket **)calloc (sizeof (hashbucket *),
-		                                       map->num_buckets + 1);
+		map->buckets = (hashbucket **)calloc (sizeof (hashbucket *), map->num_buckets);
 		if (!map->buckets) {
 			free (map);
 			return NULL;
diff --git a/tests/hash-test.c b/tests/hash-test.c
index 876088b..530c67c 100644
--- a/tests/hash-test.c
+++ b/tests/hash-test.c
@@ -171,8 +171,6 @@ test_set_clear (CuTest *tc)
 
 	map = _p11_hash_create (_p11_hash_direct_hash, _p11_hash_direct_equal, NULL, NULL);
 
-	fprintf (stderr, "%p setting\n", value);
-
 	if (!_p11_hash_set (map, key, value))
 		CuFail (tc, "should not be reached");
 
-- 
1.7.9.5

