changeset 13613:7f0f04d7017a

hash: factor, and guard against misbehaving hasher function * lib/hash.c (safe_hasher): New function, to encapsulate the checking of table->hasher's return value. Also protect against a hash value so large that adding it to table->bucket results in a NULL pointer. (hash_lookup, hash_get_next, hash_find_entry, transfer_entries): Use it in place of open-coded check-and-abort.
author Eric Blake <eblake@redhat.com>
date Tue, 31 Aug 2010 10:10:32 +0200
parents 37d5b2cb63ba
children f2950e788162
files ChangeLog lib/hash.c
diffstat 2 files changed, 26 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2010-08-31  Eric Blake  <eblake@redhat.com>
+	and Jim Meyering  <meyering@redhat.com>
+
+	hash: factor, and guard against misbehaving hasher function
+	* lib/hash.c (safe_hasher): New function, to encapsulate the checking
+	of table->hasher's return value.  Also protect against a hash value
+	so large that adding it to table->bucket results in a NULL pointer.
+	(hash_lookup, hash_get_next, hash_find_entry, transfer_entries):
+	Use it in place of open-coded check-and-abort.
+
 2010-08-30  Bruno Haible  <bruno@clisp.org>
 
 	hash: silence spurious clang warning
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -243,19 +243,26 @@
            (unsigned long int) max_bucket_length);
 }
 
+/* Hash KEY and return a pointer to the selected bucket.
+   If TABLE->hasher misbehaves, abort.  */
+static struct hash_entry const *
+safe_hasher (const Hash_table *table, const void *key)
+{
+  size_t n = table->hasher (key, table->n_buckets);
+  if (! (n < table->n_buckets))
+    abort ();
+  return table->bucket + n;
+}
+
 /* If ENTRY matches an entry already in the hash table, return the
    entry from the table.  Otherwise, return NULL.  */
 
 void *
 hash_lookup (const Hash_table *table, const void *entry)
 {
-  struct hash_entry const *bucket
-    = table->bucket + table->hasher (entry, table->n_buckets);
+  struct hash_entry const *bucket = safe_hasher (table, entry);
   struct hash_entry const *cursor;
 
-  if (! (bucket < table->bucket_limit))
-    abort ();
-
   if (bucket->data == NULL)
     return NULL;
 
@@ -299,13 +306,9 @@
 void *
 hash_get_next (const Hash_table *table, const void *entry)
 {
-  struct hash_entry const *bucket
-    = table->bucket + table->hasher (entry, table->n_buckets);
+  struct hash_entry const *bucket = safe_hasher (table, entry);
   struct hash_entry const *cursor;
 
-  if (! (bucket < table->bucket_limit))
-    abort ();
-
   /* Find next entry in the same bucket.  */
   cursor = bucket;
   do
@@ -787,13 +790,9 @@
 hash_find_entry (Hash_table *table, const void *entry,
                  struct hash_entry **bucket_head, bool delete)
 {
-  struct hash_entry *bucket
-    = table->bucket + table->hasher (entry, table->n_buckets);
+  struct hash_entry *bucket = safe_hasher (table, entry);
   struct hash_entry *cursor;
 
-  if (! (bucket < table->bucket_limit))
-    abort ();
-
   *bucket_head = bucket;
 
   /* Test for empty bucket.  */
@@ -878,10 +877,7 @@
         for (cursor = bucket->next; cursor; cursor = next)
           {
             data = cursor->data;
-            new_bucket = (dst->bucket + dst->hasher (data, dst->n_buckets));
-
-            if (! (new_bucket < dst->bucket_limit))
-              abort ();
+            new_bucket = safe_hasher (dst, data);
 
             next = cursor->next;
 
@@ -908,10 +904,7 @@
         bucket->next = NULL;
         if (safe)
           continue;
-        new_bucket = (dst->bucket + dst->hasher (data, dst->n_buckets));
-
-        if (! (new_bucket < dst->bucket_limit))
-          abort ();
+        new_bucket = safe_hasher (dst, data);
 
         if (new_bucket->data)
           {