Module: Mesa Branch: staging/23.3 Commit: 0594f8ec768692842321464a58af15bc7c89e68a URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=0594f8ec768692842321464a58af15bc7c89e68a
Author: Boris Brezillon <boris.brezil...@collabora.com> Date: Fri Dec 1 19:12:08 2023 +0100 util/hash_table: Don't leak hash_u64_key objects when the entry exists When an entry exists, _mesa_hash_table_insert() updates the entry with the new data/key pair, which causes a leak if the key has previously been dynamically allocated, like is the case for hash_u64_key keys. One solution to solve that is to do the insertion in two steps: first _mesa_hash_table_search_pre_hashed(), and if the entry doesn't exist _mesa_hash_table_insert_pre_hashed(). But approach forces us to do the double-hashing twice. Another approach is to extract the logic in hash_table_insert() that's responsible for the searching and entry allocation into a separate helper called hash_table_get_entry(), and keep the entry::{key,data} assignment in hash_table_insert(). This way we can re-use hash_table_get_entry() from _mesa_hash_table_u64_insert(), and lake sure we free the allocated key if the entry was already present. Fixes: 6649b840c340 ("mesa/util: add a hash table wrapper which support 64-bit keys") Cc: stable Signed-off-by: Boris Brezillon <boris.brezil...@collabora.com> Reviewed-by: Yonggang Luo <luoyongg...@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26423> (cherry picked from commit 5a60fd7b14e9a3045513a4b46ebd109c422c5b2e) --- .pick_status.json | 2 +- src/util/hash_table.c | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 48c11dd0156..93584afafa2 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -24,7 +24,7 @@ "description": "util/hash_table: Don't leak hash_u64_key objects when the entry exists", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "6649b840c34016b4753e69d4513a8d09da9febb2", "notes": null diff --git a/src/util/hash_table.c b/src/util/hash_table.c index a832d589309..652c8980b92 100644 --- a/src/util/hash_table.c +++ b/src/util/hash_table.c @@ -427,8 +427,7 @@ _mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index) } static struct hash_entry * -hash_table_insert(struct hash_table *ht, uint32_t hash, - const void *key, void *data) +hash_table_get_entry(struct hash_table *ht, uint32_t hash, const void *key) { struct hash_entry *available_entry = NULL; @@ -469,11 +468,8 @@ hash_table_insert(struct hash_table *ht, uint32_t hash, */ if (!entry_is_deleted(ht, entry) && entry->hash == hash && - ht->key_equals_function(key, entry->key)) { - entry->key = key; - entry->data = data; + ht->key_equals_function(key, entry->key)) return entry; - } hash_address += double_hash; if (hash_address >= size) @@ -484,8 +480,6 @@ hash_table_insert(struct hash_table *ht, uint32_t hash, if (entry_is_deleted(ht, available_entry)) ht->deleted_entries--; available_entry->hash = hash; - available_entry->key = key; - available_entry->data = data; ht->entries++; return available_entry; } @@ -496,6 +490,20 @@ hash_table_insert(struct hash_table *ht, uint32_t hash, return NULL; } +static struct hash_entry * +hash_table_insert(struct hash_table *ht, uint32_t hash, + const void *key, void *data) +{ + struct hash_entry *entry = hash_table_get_entry(ht, hash, key); + + if (entry) { + entry->key = key; + entry->data = data; + } + + return entry; +} + /** * Inserts the key with the given hash into the table. * @@ -847,7 +855,19 @@ _mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key, return; _key->value = key; - _mesa_hash_table_insert(ht->table, _key, data); + struct hash_entry *entry = + hash_table_get_entry(ht->table, key_u64_hash(_key), _key); + + if (!entry) { + FREE(_key); + return; + } + + entry->data = data; + if (!entry_is_present(ht->table, entry)) + entry->key = _key; + else + FREE(_key); } }