Skip to content

ghash: fix g_hash_table_steal_extended() when requesting key and value of a set

Thomas Haller requested to merge th/hash-steal-extended-set into main

Follow-up to !2948 (comment 1574014)

GHashTable optimizes for the "set" case, where key and value are the same. See g_hash_table_add().

A user cannot see from outside, whether a GHashTable internally is a set and shares the keys and values array. Adding one key/value pair with differing key and value, will expand the GHashTable.

In all other cases, the GHashTable API hides this implementation detail correctly. Except with g_hash_table_steal_extended(), when stealing both the key and the value.

Fix that. This bug fix is obviously a change in behavior. In practice, it's unlikely that somebody would notice, because GHashTable contains opaque pointers and the user must know what the keys/values are and be aware of their ownership semantics when stealing them. That means, the change in behavior only affects instances that are internally a set, of what the user most likely is aware and fills the table with g_hash_table_add(). Such a user would not steal both the key and values at the same time. Even if they do, then previously stealing the value was pointless and would not give them what they wanted. It would not have meaningfully worked, and since nobody reported a bug about this yet, it's unlikely somebody noticed.

The more problematic case when the user exhibits the bug is when the dictionary is unexpected a set internally. Imagine a mapping from numbers to numbers (e.g. a permutation). If "unexpectedly" the dictionary contains the identity permutation, steal-extended gives always NULL for the target number.

The example is far fetched. In practice, it's unlikely that somebody is gonna notice either way. That is not an argument for fixing anything. The argument for fixing this, is that the bug breaks the illusion that the set is only an internal optimization. That is ugly and inconsistent.

Merge request reports