From: Eric Blake Date: Tue, 31 Aug 2010 08:10:32 +0000 (+0200) Subject: hash: factor, and guard against misbehaving hasher function X-Git-Tag: v0.1~3874 X-Git-Url: http://erislabs.org.uk/gitweb/?a=commitdiff_plain;h=c0ebdfe226c38c72db7c1944113fd19ff534e362;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index a61bf9f4d..ff20e2821 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2010-08-31 Eric Blake + and Jim Meyering + + 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 hash: silence spurious clang warning diff --git a/lib/hash.c b/lib/hash.c index 225865208..a4a242057 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -243,19 +243,26 @@ hash_print_statistics (const Hash_table *table, FILE *stream) (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 @@ hash_get_first (const Hash_table *table) 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 @@ static void * 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 @@ transfer_entries (Hash_table *dst, Hash_table *src, bool safe) 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 @@ transfer_entries (Hash_table *dst, Hash_table *src, bool safe) 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) {