+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
(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;
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
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. */
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;
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)
{