diff mbox series

libsepol: optional data destruction in hashtab_destroy()

Message ID 20230714182406.28723-1-cgzones@googlemail.com (mailing list archive)
State Changes Requested
Delegated to: Petr Lautrbach
Headers show
Series libsepol: optional data destruction in hashtab_destroy() | expand

Commit Message

Christian Göttsche July 14, 2023, 6:24 p.m. UTC
Support the destruction of the hashtable entries via an optional
callback in hashtab_destroy(), to avoid iterating the hashtable twice in
common use cases, one time for the entry destruction via hashtab_map()
and a second time via hashtab_destroy() to free the hashtable itself.

Also convert all the destroy callbacks to return void instead of the
needless value of 0.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 checkpolicy/module_compiler.c                 |  6 +-
 libsepol/cil/src/cil_binary.c                 |  9 +--
 libsepol/cil/src/cil_strpool.c                |  6 +-
 libsepol/cil/src/cil_symtab.c                 |  6 +-
 libsepol/include/sepol/policydb/conditional.h |  2 +-
 libsepol/include/sepol/policydb/hashtab.h     |  8 ++-
 libsepol/include/sepol/policydb/policydb.h    |  2 +-
 libsepol/src/conditional.c                    |  3 +-
 libsepol/src/hashtab.c                        |  7 ++-
 libsepol/src/policydb.c                       | 55 +++++++------------
 libsepol/src/symtab.c                         |  3 +-
 libsepol/src/write.c                          |  6 +-
 12 files changed, 48 insertions(+), 65 deletions(-)

Comments

James Carter Aug. 1, 2023, 7:40 p.m. UTC | #1
On Fri, Jul 14, 2023 at 2:40 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Support the destruction of the hashtable entries via an optional
> callback in hashtab_destroy(), to avoid iterating the hashtable twice in
> common use cases, one time for the entry destruction via hashtab_map()
> and a second time via hashtab_destroy() to free the hashtable itself.
>
> Also convert all the destroy callbacks to return void instead of the
> needless value of 0.
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
>  checkpolicy/module_compiler.c                 |  6 +-
>  libsepol/cil/src/cil_binary.c                 |  9 +--
>  libsepol/cil/src/cil_strpool.c                |  6 +-
>  libsepol/cil/src/cil_symtab.c                 |  6 +-
>  libsepol/include/sepol/policydb/conditional.h |  2 +-
>  libsepol/include/sepol/policydb/hashtab.h     |  8 ++-
>  libsepol/include/sepol/policydb/policydb.h    |  2 +-
>  libsepol/src/conditional.c                    |  3 +-
>  libsepol/src/hashtab.c                        |  7 ++-
>  libsepol/src/policydb.c                       | 55 +++++++------------
>  libsepol/src/symtab.c                         |  3 +-
>  libsepol/src/write.c                          |  6 +-
>  12 files changed, 48 insertions(+), 65 deletions(-)
>
> diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
> index 5fe1729a..554b625f 100644
> --- a/checkpolicy/module_compiler.c
> +++ b/checkpolicy/module_compiler.c
> @@ -761,20 +761,18 @@ int add_perm_to_class(uint32_t perm_value, uint32_t class_value)
>         return 0;
>  }
>
> -static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                         __attribute__ ((unused)))
>  {
>         if (key)
>                 free(key);
>         free(datum);
> -       return 0;
>  }
>
>  static void class_datum_destroy(class_datum_t * cladatum)
>  {
>         if (cladatum != NULL) {
> -               hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
> -               hashtab_destroy(cladatum->permissions.table);
> +               hashtab_destroy(cladatum->permissions.table, perm_destroy, NULL);
>                 free(cladatum);
>         }
>  }
> diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
> index ea0cef32..8aa305c9 100644
> --- a/libsepol/cil/src/cil_binary.c
> +++ b/libsepol/cil/src/cil_binary.c
> @@ -1984,13 +1984,11 @@ exit:
>         return rc;
>  }
>
> -static int __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args)
> +static void __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args)
>  {
>         free(k);
>         ebitmap_destroy(datum);
>         free(datum);
> -
> -       return SEPOL_OK;
>  }
>
>  static int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
> @@ -5230,9 +5228,8 @@ int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p
>         rc = SEPOL_OK;
>
>  exit:
> -       hashtab_destroy(role_trans_table);
> -       hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL);
> -       hashtab_destroy(avrulex_ioctl_table);
> +       hashtab_destroy(role_trans_table, NULL, NULL);
> +       hashtab_destroy(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL);
>         free(type_value_to_cil);
>         free(class_value_to_cil);
>         if (perm_value_to_cil != NULL) {
> diff --git a/libsepol/cil/src/cil_strpool.c b/libsepol/cil/src/cil_strpool.c
> index e32ee4e9..18ecfe87 100644
> --- a/libsepol/cil/src/cil_strpool.c
> +++ b/libsepol/cil/src/cil_strpool.c
> @@ -87,12 +87,11 @@ char *cil_strpool_add(const char *str)
>         return strpool_ref->str;
>  }
>
> -static int cil_strpool_entry_destroy(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args __attribute__ ((unused)))
> +static void cil_strpool_entry_destroy(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args __attribute__ ((unused)))
>  {
>         struct cil_strpool_entry *strpool_ref = (struct cil_strpool_entry*)d;
>         free(strpool_ref->str);
>         free(strpool_ref);
> -       return SEPOL_OK;
>  }
>
>  void cil_strpool_init(void)
> @@ -115,8 +114,7 @@ void cil_strpool_destroy(void)
>         pthread_mutex_lock(&cil_strpool_mutex);
>         cil_strpool_readers--;
>         if (cil_strpool_readers == 0) {
> -               hashtab_map(cil_strpool_tab, cil_strpool_entry_destroy, NULL);
> -               hashtab_destroy(cil_strpool_tab);
> +               hashtab_destroy(cil_strpool_tab, cil_strpool_entry_destroy, NULL);
>                 cil_strpool_tab = NULL;
>         }
>         pthread_mutex_unlock(&cil_strpool_mutex);
> diff --git a/libsepol/cil/src/cil_symtab.c b/libsepol/cil/src/cil_symtab.c
> index 7e43a690..73cdd734 100644
> --- a/libsepol/cil/src/cil_symtab.c
> +++ b/libsepol/cil/src/cil_symtab.c
> @@ -133,18 +133,16 @@ int cil_symtab_map(symtab_t *symtab,
>         return hashtab_map(symtab->table, apply, args);
>  }
>
> -static int __cil_symtab_destroy_helper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, __attribute__((unused)) void *args)
> +static void __cil_symtab_destroy_helper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, __attribute__((unused)) void *args)
>  {
>         struct cil_symtab_datum *datum = d;
>         datum->symtab = NULL;
> -       return SEPOL_OK;
>  }
>
>  void cil_symtab_destroy(symtab_t *symtab)
>  {
>         if (symtab->table != NULL){
> -               cil_symtab_map(symtab, __cil_symtab_destroy_helper, NULL);
> -               hashtab_destroy(symtab->table);
> +               hashtab_destroy(symtab->table, __cil_symtab_destroy_helper, NULL);
>                 symtab->table = NULL;
>         }
>  }
> diff --git a/libsepol/include/sepol/policydb/conditional.h b/libsepol/include/sepol/policydb/conditional.h
> index 5318ea19..9b19946b 100644
> --- a/libsepol/include/sepol/policydb/conditional.h
> +++ b/libsepol/include/sepol/policydb/conditional.h
> @@ -127,7 +127,7 @@ extern void cond_policydb_destroy(policydb_t * p);
>  extern void cond_list_destroy(cond_list_t * list);
>
>  extern int cond_init_bool_indexes(policydb_t * p);
> -extern int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p);
> +extern void cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p);
>
>  extern int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum,
>                            void *datap);
> diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h
> index 354ebb43..7aa88f3b 100644
> --- a/libsepol/include/sepol/policydb/hashtab.h
> +++ b/libsepol/include/sepol/policydb/hashtab.h
> @@ -89,8 +89,14 @@ extern hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t k);
>
>  /*
>     Destroys the specified hash table.
> +   Applies the specified destroy function to (key,datum,args) for
> +   all entries.
> +
>   */
> -extern void hashtab_destroy(hashtab_t h);
> +extern void hashtab_destroy(hashtab_t h,
> +                           void (*destroy) (hashtab_key_t k,
> +                                           hashtab_datum_t d,
> +                                           void *args), void *args);
>

The args argument is never used. For hashtab_map() it is in other
cases, but not in the case of destroying the items in the hashtab.
Also, 1/3 of the calls to hashtab_destroy() do not even need to pass
in a destroy function.

I think that it would make more sense to create a new function
(without the args argument) that could be used to destroy both the
elements and the hashtab. If the destroy function is not needed, then
the old hashtab_destroy() function could be used. If something more
complex comes up in the future, there would still be the option of
using the hashtab_map()  and the hashtab_destroy() functions to deal
with it.

Thanks,
Jim


>  /*
>     Applies the specified apply function to (key,datum,args)
> diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
> index 48b7b8bb..8cf82da6 100644
> --- a/libsepol/include/sepol/policydb/policydb.h
> +++ b/libsepol/include/sepol/policydb/policydb.h
> @@ -634,7 +634,7 @@ extern int policydb_context_isvalid(const policydb_t * p,
>                                     const context_struct_t * c);
>
>  extern void symtabs_destroy(symtab_t * symtab);
> -extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
> +extern void scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
>
>  extern void class_perm_node_init(class_perm_node_t * x);
>  extern void type_set_init(type_set_t * x);
> diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c
> index 7900e928..b51639d4 100644
> --- a/libsepol/src/conditional.c
> +++ b/libsepol/src/conditional.c
> @@ -528,13 +528,12 @@ int cond_init_bool_indexes(policydb_t * p)
>         return 0;
>  }
>
> -int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
> +void cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
>                       __attribute__ ((unused)))
>  {
>         if (key)
>                 free(key);
>         free(datum);
> -       return 0;
>  }
>
>  int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
> diff --git a/libsepol/src/hashtab.c b/libsepol/src/hashtab.c
> index 922a8a4a..7f3dd00b 100644
> --- a/libsepol/src/hashtab.c
> +++ b/libsepol/src/hashtab.c
> @@ -193,7 +193,10 @@ hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t key)
>         return cur->datum;
>  }
>
> -void hashtab_destroy(hashtab_t h)
> +void hashtab_destroy(hashtab_t h,
> +                    void (*destroy) (hashtab_key_t k,
> +                                     hashtab_datum_t d,
> +                                     void *args), void *args)
>  {
>         unsigned int i;
>         hashtab_ptr_t cur, temp;
> @@ -206,6 +209,8 @@ void hashtab_destroy(hashtab_t h)
>                 while (cur != NULL) {
>                         temp = cur;
>                         cur = cur->next;
> +                       if (destroy)
> +                               destroy(temp->key, temp->datum, args);
>                         free(temp);
>                 }
>                 h->htable[i] = NULL;
> diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> index 552eb77a..f443ea88 100644
> --- a/libsepol/src/policydb.c
> +++ b/libsepol/src/policydb.c
> @@ -895,10 +895,10 @@ int policydb_init(policydb_t * p)
>
>         return 0;
>  err:
> -       hashtab_destroy(p->range_tr);
> +       hashtab_destroy(p->range_tr, NULL, NULL);
>         for (i = 0; i < SYM_NUM; i++) {
> -               hashtab_destroy(p->symtab[i].table);
> -               hashtab_destroy(p->scope[i].table);
> +               hashtab_destroy(p->symtab[i].table, NULL, NULL);
> +               hashtab_destroy(p->scope[i].table, NULL, NULL);
>         }
>         avrule_block_list_destroy(p->global);
>         return rc;
> @@ -1264,16 +1264,15 @@ int policydb_index_others(sepol_handle_t * handle,
>   * symbol data in the policy database.
>   */
>
> -static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                         __attribute__ ((unused)))
>  {
>         if (key)
>                 free(key);
>         free(datum);
> -       return 0;
>  }
>
> -static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                           __attribute__ ((unused)))
>  {
>         common_datum_t *comdatum;
> @@ -1281,13 +1280,11 @@ static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>         if (key)
>                 free(key);
>         comdatum = (common_datum_t *) datum;
> -       (void)hashtab_map(comdatum->permissions.table, perm_destroy, 0);
> -       hashtab_destroy(comdatum->permissions.table);
> +       hashtab_destroy(comdatum->permissions.table, perm_destroy, NULL);
>         free(datum);
> -       return 0;
>  }
>
> -static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                          __attribute__ ((unused)))
>  {
>         class_datum_t *cladatum;
> @@ -1297,10 +1294,9 @@ static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                 free(key);
>         cladatum = (class_datum_t *) datum;
>         if (cladatum == NULL) {
> -               return 0;
> +               return;
>         }
> -       (void)hashtab_map(cladatum->permissions.table, perm_destroy, 0);
> -       hashtab_destroy(cladatum->permissions.table);
> +       hashtab_destroy(cladatum->permissions.table, perm_destroy, NULL);
>         constraint = cladatum->constraints;
>         while (constraint) {
>                 constraint_expr_destroy(constraint->expr);
> @@ -1320,37 +1316,33 @@ static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>         if (cladatum->comkey)
>                 free(cladatum->comkey);
>         free(datum);
> -       return 0;
>  }
>
> -static int role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                         __attribute__ ((unused)))
>  {
>         free(key);
>         role_datum_destroy((role_datum_t *) datum);
>         free(datum);
> -       return 0;
>  }
>
> -static int type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                         __attribute__ ((unused)))
>  {
>         free(key);
>         type_datum_destroy((type_datum_t *) datum);
>         free(datum);
> -       return 0;
>  }
>
> -static int user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                         __attribute__ ((unused)))
>  {
>         free(key);
>         user_datum_destroy((user_datum_t *) datum);
>         free(datum);
> -       return 0;
>  }
>
> -static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                         __attribute__ ((unused)))
>  {
>         level_datum_t *levdatum;
> @@ -1362,25 +1354,23 @@ static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>         free(levdatum->level);
>         level_datum_destroy(levdatum);
>         free(levdatum);
> -       return 0;
>  }
>
> -static int cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +static void cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                        __attribute__ ((unused)))
>  {
>         if (key)
>                 free(key);
>         cat_datum_destroy((cat_datum_t *) datum);
>         free(datum);
> -       return 0;
>  }
>
> -static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
> +static void (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
>                                   void *datap) = {
>  common_destroy, class_destroy, role_destroy, type_destroy, user_destroy,
>             cond_destroy_bool, sens_destroy, cat_destroy,};
>
> -static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
> +static void range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
>                             void *p __attribute__ ((unused)))
>  {
>         struct mls_range *rt = (struct mls_range *)datum;
> @@ -1388,7 +1378,6 @@ static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
>         ebitmap_destroy(&rt->level[0].cat);
>         ebitmap_destroy(&rt->level[1].cat);
>         free(datum);
> -       return 0;
>  }
>
>  static void ocontext_selinux_free(ocontext_t **ocontexts)
> @@ -1468,8 +1457,7 @@ void policydb_destroy(policydb_t * p)
>         free(p->decl_val_to_struct);
>
>         for (i = 0; i < SYM_NUM; i++) {
> -               (void)hashtab_map(p->scope[i].table, scope_destroy, 0);
> -               hashtab_destroy(p->scope[i].table);
> +               hashtab_destroy(p->scope[i].table, scope_destroy, NULL);
>         }
>         avrule_block_list_destroy(p->global);
>         free(p->name);
> @@ -1515,8 +1503,7 @@ void policydb_destroy(policydb_t * p)
>         if (lra)
>                 free(lra);
>
> -       hashtab_map(p->range_tr, range_tr_destroy, NULL);
> -       hashtab_destroy(p->range_tr);
> +       hashtab_destroy(p->range_tr, range_tr_destroy, NULL);
>
>         if (p->type_attr_map) {
>                 for (i = 0; i < p->p_types.nprim; i++) {
> @@ -1539,12 +1526,11 @@ void symtabs_destroy(symtab_t * symtab)
>  {
>         int i;
>         for (i = 0; i < SYM_NUM; i++) {
> -               (void)hashtab_map(symtab[i].table, destroy_f[i], 0);
> -               hashtab_destroy(symtab[i].table);
> +               hashtab_destroy(symtab[i].table, destroy_f[i], NULL);
>         }
>  }
>
> -int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
> +void scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                   __attribute__ ((unused)))
>  {
>         scope_datum_t *cur = (scope_datum_t *) datum;
> @@ -1553,7 +1539,6 @@ int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
>                 free(cur->decl_ids);
>         }
>         free(cur);
> -       return 0;
>  }
>
>  /*
> diff --git a/libsepol/src/symtab.c b/libsepol/src/symtab.c
> index a6061851..3430bfc0 100644
> --- a/libsepol/src/symtab.c
> +++ b/libsepol/src/symtab.c
> @@ -51,7 +51,6 @@ void symtab_destroy(symtab_t * s)
>         if (!s)
>                 return;
>         if (s->table)
> -               hashtab_destroy(s->table);
> -       return;
> +               hashtab_destroy(s->table, NULL, NULL);
>  }
>  /* FLASK */
> diff --git a/libsepol/src/write.c b/libsepol/src/write.c
> index f0ed9e33..2eb08bb7 100644
> --- a/libsepol/src/write.c
> +++ b/libsepol/src/write.c
> @@ -539,7 +539,7 @@ static int filenametr_cmp(hashtab_t h __attribute__ ((unused)),
>         return strcmp(ft1->name, ft2->name);
>  }
>
> -static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
> +static void filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
>                               void *p __attribute__ ((unused)))
>  {
>         filenametr_key_t *ft = (filenametr_key_t *)key;
> @@ -553,7 +553,6 @@ static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
>                 free(fd);
>                 fd = next;
>         } while (fd);
> -       return 0;
>  }
>
>  typedef struct {
> @@ -778,8 +777,7 @@ static int avtab_filename_trans_write(policydb_t *pol, avtab_t *a,
>
>  out:
>         /* destroy temp filename transitions table */
> -       hashtab_map(fnts_tab, filenametr_destroy, NULL);
> -       hashtab_destroy(fnts_tab);
> +       hashtab_destroy(fnts_tab, filenametr_destroy, NULL);
>
>         return rc ? -1 : 0;
>  }
> --
> 2.40.1
>
diff mbox series

Patch

diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c
index 5fe1729a..554b625f 100644
--- a/checkpolicy/module_compiler.c
+++ b/checkpolicy/module_compiler.c
@@ -761,20 +761,18 @@  int add_perm_to_class(uint32_t perm_value, uint32_t class_value)
 	return 0;
 }
 
-static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			__attribute__ ((unused)))
 {
 	if (key)
 		free(key);
 	free(datum);
-	return 0;
 }
 
 static void class_datum_destroy(class_datum_t * cladatum)
 {
 	if (cladatum != NULL) {
-		hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
-		hashtab_destroy(cladatum->permissions.table);
+		hashtab_destroy(cladatum->permissions.table, perm_destroy, NULL);
 		free(cladatum);
 	}
 }
diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c
index ea0cef32..8aa305c9 100644
--- a/libsepol/cil/src/cil_binary.c
+++ b/libsepol/cil/src/cil_binary.c
@@ -1984,13 +1984,11 @@  exit:
 	return rc;
 }
 
-static int __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args)
+static void __cil_avrulex_ioctl_destroy(hashtab_key_t k, hashtab_datum_t datum, __attribute__((unused)) void *args)
 {
 	free(k);
 	ebitmap_destroy(datum);
 	free(datum);
-
-	return SEPOL_OK;
 }
 
 static int __cil_cond_to_policydb_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
@@ -5230,9 +5228,8 @@  int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *p
 	rc = SEPOL_OK;
 
 exit:
-	hashtab_destroy(role_trans_table);
-	hashtab_map(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL);
-	hashtab_destroy(avrulex_ioctl_table);
+	hashtab_destroy(role_trans_table, NULL, NULL);
+	hashtab_destroy(avrulex_ioctl_table, __cil_avrulex_ioctl_destroy, NULL);
 	free(type_value_to_cil);
 	free(class_value_to_cil);
 	if (perm_value_to_cil != NULL) {
diff --git a/libsepol/cil/src/cil_strpool.c b/libsepol/cil/src/cil_strpool.c
index e32ee4e9..18ecfe87 100644
--- a/libsepol/cil/src/cil_strpool.c
+++ b/libsepol/cil/src/cil_strpool.c
@@ -87,12 +87,11 @@  char *cil_strpool_add(const char *str)
 	return strpool_ref->str;
 }
 
-static int cil_strpool_entry_destroy(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args __attribute__ ((unused)))
+static void cil_strpool_entry_destroy(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args __attribute__ ((unused)))
 {
 	struct cil_strpool_entry *strpool_ref = (struct cil_strpool_entry*)d;
 	free(strpool_ref->str);
 	free(strpool_ref);
-	return SEPOL_OK;
 }
 
 void cil_strpool_init(void)
@@ -115,8 +114,7 @@  void cil_strpool_destroy(void)
 	pthread_mutex_lock(&cil_strpool_mutex);
 	cil_strpool_readers--;
 	if (cil_strpool_readers == 0) {
-		hashtab_map(cil_strpool_tab, cil_strpool_entry_destroy, NULL);
-		hashtab_destroy(cil_strpool_tab);
+		hashtab_destroy(cil_strpool_tab, cil_strpool_entry_destroy, NULL);
 		cil_strpool_tab = NULL;
 	}
 	pthread_mutex_unlock(&cil_strpool_mutex);
diff --git a/libsepol/cil/src/cil_symtab.c b/libsepol/cil/src/cil_symtab.c
index 7e43a690..73cdd734 100644
--- a/libsepol/cil/src/cil_symtab.c
+++ b/libsepol/cil/src/cil_symtab.c
@@ -133,18 +133,16 @@  int cil_symtab_map(symtab_t *symtab,
 	return hashtab_map(symtab->table, apply, args);
 }
 
-static int __cil_symtab_destroy_helper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, __attribute__((unused)) void *args)
+static void __cil_symtab_destroy_helper(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, __attribute__((unused)) void *args)
 {
 	struct cil_symtab_datum *datum = d;
 	datum->symtab = NULL;
-	return SEPOL_OK;
 }
 
 void cil_symtab_destroy(symtab_t *symtab)
 {
 	if (symtab->table != NULL){
-		cil_symtab_map(symtab, __cil_symtab_destroy_helper, NULL);
-		hashtab_destroy(symtab->table);
+		hashtab_destroy(symtab->table, __cil_symtab_destroy_helper, NULL);
 		symtab->table = NULL;
 	}
 }
diff --git a/libsepol/include/sepol/policydb/conditional.h b/libsepol/include/sepol/policydb/conditional.h
index 5318ea19..9b19946b 100644
--- a/libsepol/include/sepol/policydb/conditional.h
+++ b/libsepol/include/sepol/policydb/conditional.h
@@ -127,7 +127,7 @@  extern void cond_policydb_destroy(policydb_t * p);
 extern void cond_list_destroy(cond_list_t * list);
 
 extern int cond_init_bool_indexes(policydb_t * p);
-extern int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p);
+extern void cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p);
 
 extern int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum,
 			   void *datap);
diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h
index 354ebb43..7aa88f3b 100644
--- a/libsepol/include/sepol/policydb/hashtab.h
+++ b/libsepol/include/sepol/policydb/hashtab.h
@@ -89,8 +89,14 @@  extern hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t k);
 
 /*
    Destroys the specified hash table.
+   Applies the specified destroy function to (key,datum,args) for
+   all entries.
+
  */
-extern void hashtab_destroy(hashtab_t h);
+extern void hashtab_destroy(hashtab_t h,
+			    void (*destroy) (hashtab_key_t k,
+					    hashtab_datum_t d,
+					    void *args), void *args);
 
 /*
    Applies the specified apply function to (key,datum,args)
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index 48b7b8bb..8cf82da6 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -634,7 +634,7 @@  extern int policydb_context_isvalid(const policydb_t * p,
 				    const context_struct_t * c);
 
 extern void symtabs_destroy(symtab_t * symtab);
-extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
+extern void scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
 
 extern void class_perm_node_init(class_perm_node_t * x);
 extern void type_set_init(type_set_t * x);
diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c
index 7900e928..b51639d4 100644
--- a/libsepol/src/conditional.c
+++ b/libsepol/src/conditional.c
@@ -528,13 +528,12 @@  int cond_init_bool_indexes(policydb_t * p)
 	return 0;
 }
 
-int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
+void cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
 		      __attribute__ ((unused)))
 {
 	if (key)
 		free(key);
 	free(datum);
-	return 0;
 }
 
 int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
diff --git a/libsepol/src/hashtab.c b/libsepol/src/hashtab.c
index 922a8a4a..7f3dd00b 100644
--- a/libsepol/src/hashtab.c
+++ b/libsepol/src/hashtab.c
@@ -193,7 +193,10 @@  hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t key)
 	return cur->datum;
 }
 
-void hashtab_destroy(hashtab_t h)
+void hashtab_destroy(hashtab_t h,
+		     void (*destroy) (hashtab_key_t k,
+				      hashtab_datum_t d,
+				      void *args), void *args)
 {
 	unsigned int i;
 	hashtab_ptr_t cur, temp;
@@ -206,6 +209,8 @@  void hashtab_destroy(hashtab_t h)
 		while (cur != NULL) {
 			temp = cur;
 			cur = cur->next;
+			if (destroy)
+				destroy(temp->key, temp->datum, args);
 			free(temp);
 		}
 		h->htable[i] = NULL;
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 552eb77a..f443ea88 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -895,10 +895,10 @@  int policydb_init(policydb_t * p)
 
 	return 0;
 err:
-	hashtab_destroy(p->range_tr);
+	hashtab_destroy(p->range_tr, NULL, NULL);
 	for (i = 0; i < SYM_NUM; i++) {
-		hashtab_destroy(p->symtab[i].table);
-		hashtab_destroy(p->scope[i].table);
+		hashtab_destroy(p->symtab[i].table, NULL, NULL);
+		hashtab_destroy(p->scope[i].table, NULL, NULL);
 	}
 	avrule_block_list_destroy(p->global);
 	return rc;
@@ -1264,16 +1264,15 @@  int policydb_index_others(sepol_handle_t * handle,
  * symbol data in the policy database.
  */
 
-static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			__attribute__ ((unused)))
 {
 	if (key)
 		free(key);
 	free(datum);
-	return 0;
 }
 
-static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			  __attribute__ ((unused)))
 {
 	common_datum_t *comdatum;
@@ -1281,13 +1280,11 @@  static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 	if (key)
 		free(key);
 	comdatum = (common_datum_t *) datum;
-	(void)hashtab_map(comdatum->permissions.table, perm_destroy, 0);
-	hashtab_destroy(comdatum->permissions.table);
+	hashtab_destroy(comdatum->permissions.table, perm_destroy, NULL);
 	free(datum);
-	return 0;
 }
 
-static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			 __attribute__ ((unused)))
 {
 	class_datum_t *cladatum;
@@ -1297,10 +1294,9 @@  static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 		free(key);
 	cladatum = (class_datum_t *) datum;
 	if (cladatum == NULL) {
-		return 0;
+		return;
 	}
-	(void)hashtab_map(cladatum->permissions.table, perm_destroy, 0);
-	hashtab_destroy(cladatum->permissions.table);
+	hashtab_destroy(cladatum->permissions.table, perm_destroy, NULL);
 	constraint = cladatum->constraints;
 	while (constraint) {
 		constraint_expr_destroy(constraint->expr);
@@ -1320,37 +1316,33 @@  static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 	if (cladatum->comkey)
 		free(cladatum->comkey);
 	free(datum);
-	return 0;
 }
 
-static int role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			__attribute__ ((unused)))
 {
 	free(key);
 	role_datum_destroy((role_datum_t *) datum);
 	free(datum);
-	return 0;
 }
 
-static int type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			__attribute__ ((unused)))
 {
 	free(key);
 	type_datum_destroy((type_datum_t *) datum);
 	free(datum);
-	return 0;
 }
 
-static int user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			__attribute__ ((unused)))
 {
 	free(key);
 	user_datum_destroy((user_datum_t *) datum);
 	free(datum);
-	return 0;
 }
 
-static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 			__attribute__ ((unused)))
 {
 	level_datum_t *levdatum;
@@ -1362,25 +1354,23 @@  static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 	free(levdatum->level);
 	level_datum_destroy(levdatum);
 	free(levdatum);
-	return 0;
 }
 
-static int cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+static void cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 		       __attribute__ ((unused)))
 {
 	if (key)
 		free(key);
 	cat_datum_destroy((cat_datum_t *) datum);
 	free(datum);
-	return 0;
 }
 
-static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
+static void (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum,
 				  void *datap) = {
 common_destroy, class_destroy, role_destroy, type_destroy, user_destroy,
 	    cond_destroy_bool, sens_destroy, cat_destroy,};
 
-static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
+static void range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
 			    void *p __attribute__ ((unused)))
 {
 	struct mls_range *rt = (struct mls_range *)datum;
@@ -1388,7 +1378,6 @@  static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum,
 	ebitmap_destroy(&rt->level[0].cat);
 	ebitmap_destroy(&rt->level[1].cat);
 	free(datum);
-	return 0;
 }
 
 static void ocontext_selinux_free(ocontext_t **ocontexts)
@@ -1468,8 +1457,7 @@  void policydb_destroy(policydb_t * p)
 	free(p->decl_val_to_struct);
 
 	for (i = 0; i < SYM_NUM; i++) {
-		(void)hashtab_map(p->scope[i].table, scope_destroy, 0);
-		hashtab_destroy(p->scope[i].table);
+		hashtab_destroy(p->scope[i].table, scope_destroy, NULL);
 	}
 	avrule_block_list_destroy(p->global);
 	free(p->name);
@@ -1515,8 +1503,7 @@  void policydb_destroy(policydb_t * p)
 	if (lra)
 		free(lra);
 
-	hashtab_map(p->range_tr, range_tr_destroy, NULL);
-	hashtab_destroy(p->range_tr);
+	hashtab_destroy(p->range_tr, range_tr_destroy, NULL);
 
 	if (p->type_attr_map) {
 		for (i = 0; i < p->p_types.nprim; i++) {
@@ -1539,12 +1526,11 @@  void symtabs_destroy(symtab_t * symtab)
 {
 	int i;
 	for (i = 0; i < SYM_NUM; i++) {
-		(void)hashtab_map(symtab[i].table, destroy_f[i], 0);
-		hashtab_destroy(symtab[i].table);
+		hashtab_destroy(symtab[i].table, destroy_f[i], NULL);
 	}
 }
 
-int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
+void scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 		  __attribute__ ((unused)))
 {
 	scope_datum_t *cur = (scope_datum_t *) datum;
@@ -1553,7 +1539,6 @@  int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
 		free(cur->decl_ids);
 	}
 	free(cur);
-	return 0;
 }
 
 /*
diff --git a/libsepol/src/symtab.c b/libsepol/src/symtab.c
index a6061851..3430bfc0 100644
--- a/libsepol/src/symtab.c
+++ b/libsepol/src/symtab.c
@@ -51,7 +51,6 @@  void symtab_destroy(symtab_t * s)
 	if (!s)
 		return;
 	if (s->table)
-		hashtab_destroy(s->table);
-	return;
+		hashtab_destroy(s->table, NULL, NULL);
 }
 /* FLASK */
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index f0ed9e33..2eb08bb7 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -539,7 +539,7 @@  static int filenametr_cmp(hashtab_t h __attribute__ ((unused)),
 	return strcmp(ft1->name, ft2->name);
 }
 
-static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
+static void filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
 			      void *p __attribute__ ((unused)))
 {
 	filenametr_key_t *ft = (filenametr_key_t *)key;
@@ -553,7 +553,6 @@  static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum,
 		free(fd);
 		fd = next;
 	} while (fd);
-	return 0;
 }
 
 typedef struct {
@@ -778,8 +777,7 @@  static int avtab_filename_trans_write(policydb_t *pol, avtab_t *a,
 
 out:
 	/* destroy temp filename transitions table */
-	hashtab_map(fnts_tab, filenametr_destroy, NULL);
-	hashtab_destroy(fnts_tab);
+	hashtab_destroy(fnts_tab, filenametr_destroy, NULL);
 
 	return rc ? -1 : 0;
 }