Fix undefined function pointer casts in LHASH.

Bug: chromium:785442
Change-Id: I516e42684b913dc0de778dd9134f1ca108c04dfc
Reviewed-on: https://boringssl-review.googlesource.com/c/32120
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c
index e4fc3fd..98ee60a 100644
--- a/crypto/lhash/lhash.c
+++ b/crypto/lhash/lhash.c
@@ -139,15 +139,17 @@
 // not found, it returns a pointer that points to a NULL pointer. If |out_hash|
 // is not NULL, then it also puts the hash value of |data| in |*out_hash|.
 static LHASH_ITEM **get_next_ptr_and_hash(const _LHASH *lh, uint32_t *out_hash,
-                                          const void *data) {
-  const uint32_t hash = lh->hash(data);
+                                          const void *data,
+                                          lhash_hash_func_helper call_hash_func,
+                                          lhash_cmp_func_helper call_cmp_func) {
+  const uint32_t hash = call_hash_func(lh->hash, data);
   if (out_hash != NULL) {
     *out_hash = hash;
   }
 
   LHASH_ITEM **ret = &lh->buckets[hash % lh->num_buckets];
   for (LHASH_ITEM *cur = *ret; cur != NULL; cur = *ret) {
-    if (lh->comp(cur->data, data) == 0) {
+    if (call_cmp_func(lh->comp, cur->data, data) == 0) {
       break;
     }
     ret = &cur->next;
@@ -173,8 +175,11 @@
   return ret;
 }
 
-void *lh_retrieve(const _LHASH *lh, const void *data) {
-  LHASH_ITEM **next_ptr = get_next_ptr_and_hash(lh, NULL, data);
+void *lh_retrieve(const _LHASH *lh, const void *data,
+                  lhash_hash_func_helper call_hash_func,
+                  lhash_cmp_func_helper call_cmp_func) {
+  LHASH_ITEM **next_ptr =
+      get_next_ptr_and_hash(lh, NULL, data, call_hash_func, call_cmp_func);
   return *next_ptr == NULL ? NULL : (*next_ptr)->data;
 }
 
@@ -247,12 +252,15 @@
   }
 }
 
-int lh_insert(_LHASH *lh, void **old_data, void *data) {
+int lh_insert(_LHASH *lh, void **old_data, void *data,
+              lhash_hash_func_helper call_hash_func,
+              lhash_cmp_func_helper call_cmp_func) {
   uint32_t hash;
   LHASH_ITEM **next_ptr, *item;
 
   *old_data = NULL;
-  next_ptr = get_next_ptr_and_hash(lh, &hash, data);
+  next_ptr =
+      get_next_ptr_and_hash(lh, &hash, data, call_hash_func, call_cmp_func);
 
 
   if (*next_ptr != NULL) {
@@ -279,10 +287,13 @@
   return 1;
 }
 
-void *lh_delete(_LHASH *lh, const void *data) {
+void *lh_delete(_LHASH *lh, const void *data,
+                lhash_hash_func_helper call_hash_func,
+                lhash_cmp_func_helper call_cmp_func) {
   LHASH_ITEM **next_ptr, *item, *ret;
 
-  next_ptr = get_next_ptr_and_hash(lh, NULL, data);
+  next_ptr =
+      get_next_ptr_and_hash(lh, NULL, data, call_hash_func, call_cmp_func);
 
   if (*next_ptr == NULL) {
     // No such element.
@@ -300,8 +311,7 @@
   return ret;
 }
 
-static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *),
-                              void (*arg_func)(void *, void *), void *arg) {
+void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) {
   if (lh == NULL) {
     return;
   }
@@ -315,11 +325,7 @@
     LHASH_ITEM *next;
     for (LHASH_ITEM *cur = lh->buckets[i]; cur != NULL; cur = next) {
       next = cur->next;
-      if (arg_func) {
-        arg_func(cur->data, arg);
-      } else {
-        no_arg_func(cur->data);
-      }
+      func(cur->data, arg);
     }
   }
 
@@ -333,14 +339,6 @@
   lh_maybe_resize(lh);
 }
 
-void lh_doall(_LHASH *lh, void (*func)(void *)) {
-  lh_doall_internal(lh, func, NULL, NULL);
-}
-
-void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) {
-  lh_doall_internal(lh, NULL, func, arg);
-}
-
 uint32_t lh_strhash(const char *c) {
   if (c == NULL) {
     return 0;
diff --git a/include/openssl/lhash.h b/include/openssl/lhash.h
index 77ca493..c82bb8e 100644
--- a/include/openssl/lhash.h
+++ b/include/openssl/lhash.h
@@ -104,11 +104,22 @@
 // equal, to zero depending on whether |*a| is equal, or not equal to |*b|,
 // respectively. Note the difference between this and |stack_cmp_func| in that
 // this takes pointers to the objects directly.
+//
+// This function's actual type signature is int (*)(const T*, const T*). The
+// low-level |lh_*| functions will be passed a type-specific wrapper to call it
+// correctly.
 typedef int (*lhash_cmp_func)(const void *a, const void *b);
+typedef int (*lhash_cmp_func_helper)(lhash_cmp_func func, const void *a,
+                                     const void *b);
 
 // lhash_hash_func is a function that maps an object to a uniformly distributed
 // uint32_t.
+//
+// This function's actual type signature is uint32_t (*)(const T*). The
+// low-level |lh_*| functions will be passed a type-specific wrapper to call it
+// correctly.
 typedef uint32_t (*lhash_hash_func)(const void *a);
+typedef uint32_t (*lhash_hash_func_helper)(lhash_hash_func func, const void *a);
 
 typedef struct lhash_st _LHASH;
 
@@ -124,7 +135,9 @@
 
 // lh_retrieve finds an element equal to |data| in the hash table and returns
 // it. If no such element exists, it returns NULL.
-OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data);
+OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data,
+                                 lhash_hash_func_helper call_hash_func,
+                                 lhash_cmp_func_helper call_cmp_func);
 
 // lh_retrieve_key finds an element matching |key|, given the specified hash and
 // comparison function. This differs from |lh_retrieve| in that the key may be a
@@ -140,15 +153,15 @@
 // will be set to that value and it will be replaced. Otherwise, or in the
 // event of an error, |*old_data| will be set to NULL. It returns one on
 // success or zero in the case of an allocation error.
-OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data);
+OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data,
+                             lhash_hash_func_helper call_hash_func,
+                             lhash_cmp_func_helper call_cmp_func);
 
 // lh_delete removes an element equal to |data| from the hash table and returns
 // it. If no such element is found, it returns NULL.
-OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data);
-
-// lh_doall calls |func| on each element of the hash table.
-// TODO(fork): rename this
-OPENSSL_EXPORT void lh_doall(_LHASH *lh, void (*func)(void *));
+OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data,
+                               lhash_hash_func_helper call_hash_func,
+                               lhash_cmp_func_helper call_cmp_func);
 
 // lh_doall_arg calls |func| on each element of the hash table and also passes
 // |arg| as the second argument.
@@ -166,6 +179,16 @@
   typedef int (*lhash_##type##_cmp_func)(const type *, const type *);          \
   typedef uint32_t (*lhash_##type##_hash_func)(const type *);                  \
                                                                                \
+  OPENSSL_INLINE int lh_##type##_call_cmp_func(lhash_cmp_func func,            \
+                                               const void *a, const void *b) { \
+    return ((lhash_##type##_cmp_func)func)((const type *)a, (const type *)b);  \
+  }                                                                            \
+                                                                               \
+  OPENSSL_INLINE uint32_t lh_##type##_call_hash_func(lhash_hash_func func,     \
+                                                     const void *a) {          \
+    return ((lhash_##type##_hash_func)func)((const type *)a);                  \
+  }                                                                            \
+                                                                               \
   OPENSSL_INLINE LHASH_OF(type) *                                              \
       lh_##type##_new(lhash_##type##_hash_func hash,                           \
                       lhash_##type##_cmp_func comp) {                          \
@@ -183,38 +206,72 @@
                                                                                \
   OPENSSL_INLINE type *lh_##type##_retrieve(const LHASH_OF(type) *lh,          \
                                             const type *data) {                \
-    return (type *)lh_retrieve((const _LHASH *)lh, data);                      \
+    return (type *)lh_retrieve((const _LHASH *)lh, data,                       \
+                               lh_##type##_call_hash_func,                     \
+                               lh_##type##_call_cmp_func);                     \
+  }                                                                            \
+                                                                               \
+  typedef struct {                                                             \
+    int (*cmp_key)(const void *key, const type *value);                        \
+    const void *key;                                                           \
+  } LHASH_CMP_KEY_##type;                                                      \
+                                                                               \
+  OPENSSL_INLINE int lh_##type##_call_cmp_key(const void *key,                 \
+                                              const void *value) {             \
+    const LHASH_CMP_KEY_##type *cb = (const LHASH_CMP_KEY_##type *)key;        \
+    return cb->cmp_key(cb->key, (const type *)value);                          \
   }                                                                            \
                                                                                \
   OPENSSL_INLINE type *lh_##type##_retrieve_key(                               \
       const LHASH_OF(type) *lh, const void *key, uint32_t key_hash,            \
       int (*cmp_key)(const void *key, const type *value)) {                    \
-    return (type *)lh_retrieve_key(                                            \
-        (const _LHASH *)lh, key, key_hash,                                     \
-        (int (*)(const void *, const void *))cmp_key);                         \
+    LHASH_CMP_KEY_##type cb = {cmp_key, key};                                  \
+    return (type *)lh_retrieve_key((const _LHASH *)lh, &cb, key_hash,          \
+                                   lh_##type##_call_cmp_key);                  \
   }                                                                            \
                                                                                \
   OPENSSL_INLINE int lh_##type##_insert(LHASH_OF(type) *lh, type **old_data,   \
                                         type *data) {                          \
     void *old_data_void = NULL;                                                \
-    int ret = lh_insert((_LHASH *)lh, &old_data_void, data);                   \
+    int ret =                                                                  \
+        lh_insert((_LHASH *)lh, &old_data_void, data,                          \
+                  lh_##type##_call_hash_func, lh_##type##_call_cmp_func);      \
     *old_data = (type *)old_data_void;                                         \
     return ret;                                                                \
   }                                                                            \
                                                                                \
   OPENSSL_INLINE type *lh_##type##_delete(LHASH_OF(type) *lh,                  \
                                           const type *data) {                  \
-    return (type *)lh_delete((_LHASH *)lh, data);                              \
+    return (type *)lh_delete((_LHASH *)lh, data, lh_##type##_call_hash_func,   \
+                             lh_##type##_call_cmp_func);                       \
+  }                                                                            \
+                                                                               \
+  typedef struct {                                                             \
+    void (*doall)(type *);                                                     \
+    void (*doall_arg)(type *, void *);                                         \
+    void *arg;                                                                 \
+  } LHASH_DOALL_##type;                                                        \
+                                                                               \
+  OPENSSL_INLINE void lh_##type##_call_doall(void *value, void *arg) {         \
+    const LHASH_DOALL_##type *cb = (const LHASH_DOALL_##type *)arg;            \
+    cb->doall((type *)value);                                                  \
+  }                                                                            \
+                                                                               \
+  OPENSSL_INLINE void lh_##type##_call_doall_arg(void *value, void *arg) {     \
+    const LHASH_DOALL_##type *cb = (const LHASH_DOALL_##type *)arg;            \
+    cb->doall_arg((type *)value, cb->arg);                                     \
   }                                                                            \
                                                                                \
   OPENSSL_INLINE void lh_##type##_doall(LHASH_OF(type) *lh,                    \
                                         void (*func)(type *)) {                \
-    lh_doall((_LHASH *)lh, (void (*)(void *))func);                            \
+    LHASH_DOALL_##type cb = {func, NULL, NULL};                                \
+    lh_doall_arg((_LHASH *)lh, lh_##type##_call_doall, &cb);                   \
   }                                                                            \
                                                                                \
   OPENSSL_INLINE void lh_##type##_doall_arg(                                   \
       LHASH_OF(type) *lh, void (*func)(type *, void *), void *arg) {           \
-    lh_doall_arg((_LHASH *)lh, (void (*)(void *, void *))func, arg);           \
+    LHASH_DOALL_##type cb = {NULL, func, arg};                                 \
+    lh_doall_arg((_LHASH *)lh, lh_##type##_call_doall_arg, &cb);               \
   }