summaryrefslogtreecommitdiff
path: root/lib/hash.c
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2009-06-17 13:01:41 -0600
committerJim Meyering <meyering@redhat.com>2009-06-18 09:12:06 +0200
commit1d1b26278aece6b648d6d8ffffdae809cfd95973 (patch)
tree430034750280b1750974079f2323d06574d24db9 /lib/hash.c
parentae156c0bf8058d3c1568c1ed573a1319a451ac7e (diff)
downloadgnulib-1d1b26278aece6b648d6d8ffffdae809cfd95973.tar.gz
hash: check for resize before insertion
* lib/hash.c (hash_insert): Check whether bucket usage exceeds threshold before insertion, so that a pathological hash_rehash that fills every bucket can still trigger another rehash. Signed-off-by: Eric Blake <ebb9@byu.net>
Diffstat (limited to 'lib/hash.c')
-rw-r--r--lib/hash.c54
1 files changed, 29 insertions, 25 deletions
diff --git a/lib/hash.c b/lib/hash.c
index 5068202a3d..4de106960c 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -931,30 +931,6 @@ hash_insert (Hash_table *table, const void *entry)
if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL)
return data;
- /* ENTRY is not matched, it should be inserted. */
-
- if (bucket->data)
- {
- struct hash_entry *new_entry = allocate_entry (table);
-
- if (new_entry == NULL)
- return NULL;
-
- /* Add ENTRY in the overflow of the bucket. */
-
- new_entry->data = (void *) entry;
- new_entry->next = bucket->next;
- bucket->next = new_entry;
- table->n_entries++;
- return (void *) entry;
- }
-
- /* Add ENTRY right in the bucket head. */
-
- bucket->data = (void *) entry;
- table->n_entries++;
- table->n_buckets_used++;
-
/* If the growth threshold of the buckets in use has been reached, increase
the table size and rehash. There's no point in checking the number of
entries: if the hashing function is ill-conditioned, rehashing is not
@@ -981,10 +957,38 @@ hash_insert (Hash_table *table, const void *entry)
/* If the rehash fails, arrange to return NULL. */
if (!hash_rehash (table, candidate))
- entry = NULL;
+ return NULL;
+
+ /* Update the bucket we are interested in. */
+ if (hash_find_entry (table, entry, &bucket, false) != NULL)
+ abort ();
}
}
+ /* ENTRY is not matched, it should be inserted. */
+
+ if (bucket->data)
+ {
+ struct hash_entry *new_entry = allocate_entry (table);
+
+ if (new_entry == NULL)
+ return NULL;
+
+ /* Add ENTRY in the overflow of the bucket. */
+
+ new_entry->data = (void *) entry;
+ new_entry->next = bucket->next;
+ bucket->next = new_entry;
+ table->n_entries++;
+ return (void *) entry;
+ }
+
+ /* Add ENTRY right in the bucket head. */
+
+ bucket->data = (void *) entry;
+ table->n_entries++;
+ table->n_buckets_used++;
+
return (void *) entry;
}