From e839b0ae2e9b1d342779e723d22e6d4aa58a0da9 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 29 Nov 2023 21:02:49 +0100 Subject: [PATCH] util/hash_table: Don't leak hash_key_u64 objects when the u64 hash table is destroyed Allocate a ralloc sub-context which takes the u64 hash table as a parent and attach a destructor to it so we can free the hash_key_u64 objects that were allocated by _mesa_hash_table_u64_insert(). The order of creation of this sub-context is crucial: it needs to happen after the _mesa_hash_table_create() call to guarantee that the destructor is called before ht->table and its children are freed, otherwise the _mesa_hash_table_u64_clear() call in the destructor leads to a use-after-free situation. Fixes: ff494361bee7 ("util: rzalloc and free hash_table_u64") Cc: stable Signed-off-by: Boris Brezillon Reviewed-by: Yonggang Luo Part-of: (cherry picked from commit db5166718d89ba71f8d12fbdceffb05d7c5e9a03) --- .pick_status.json | 2 +- src/util/hash_table.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.pick_status.json b/.pick_status.json index 93584af..8e88e23 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -14,7 +14,7 @@ "description": "util/hash_table: Don't leak hash_key_u64 objects when the u64 hash table is destroyed", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "ff494361bee7506db701cb861073ab194ae3a6e9", "notes": null diff --git a/src/util/hash_table.c b/src/util/hash_table.c index 652c898..a76ebbc 100644 --- a/src/util/hash_table.c +++ b/src/util/hash_table.c @@ -777,6 +777,13 @@ key_u64_equals(const void *a, const void *b) #define FREED_KEY_VALUE 0 +static void _mesa_hash_table_u64_delete_keys(void *data) +{ + struct hash_table_u64 *ht = ralloc_parent(data); + + _mesa_hash_table_u64_clear(ht); +} + struct hash_table_u64 * _mesa_hash_table_u64_create(void *mem_ctx) { @@ -793,6 +800,31 @@ _mesa_hash_table_u64_create(void *mem_ctx) } else { ht->table = _mesa_hash_table_create(ht, key_u64_hash, key_u64_equals); + + /* Allocate a ralloc sub-context which takes the u64 hash table + * as a parent and attach a destructor to it so we can free the + * hash_key_u64 objects that were allocated by + * _mesa_hash_table_u64_insert(). + * + * The order of creation of this sub-context is crucial: it needs + * to happen after the _mesa_hash_table_create() call to guarantee + * that the destructor is called before ht->table and its children + * are freed, otherwise the _mesa_hash_table_u64_clear() call in the + * destructor leads to a use-after-free situation. + */ + if (ht->table) { + void *dummy_ctx = ralloc_context(ht); + + /* If we can't allocate a sub-context, free the hash table + * immediately and return NULL to avoid future leaks. + */ + if (!dummy_ctx) { + ralloc_free(ht); + return NULL; + } + + ralloc_set_destructor(dummy_ctx, _mesa_hash_table_u64_delete_keys); + } } if (ht->table) -- 2.7.4