ghash: Correctly retrieve low 32 bits of 64-bit values

Dereferencing a pointer to a 64-bit object as though it was a 32-bit
object is the same as taking the least significant 32 bits on a
little-endian machine, but on a big-endian machine it is the same as
taking the *most* significant 32 bits, which would result in these hash
functions always hashing to zero. The /hash/int64/collisions and
/hash/double/collisions test-cases in glib/tests/hash.c detect this
and fail.

Instead, fetch the whole 64-bit quantity and do the bit-manipulation
to xor the more significant half with the less significant half in an
architecture-neutral way.

Fixes: dd1f4f70 "Optimize g_double_hash implementation"
Fixes: c1af4b2b "Optional optimization for `g_int64_hash`"
Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2787
Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie 2022-10-21 10:16:27 +01:00 committed by Philip Withnall
parent 662661a8d0
commit de7abf54c7

View File

@ -2496,7 +2496,9 @@ g_int64_equal (gconstpointer v1,
guint
g_int64_hash (gconstpointer v)
{
return (guint) ((const guint) (*(guint64 *) v >> 32)) ^ (*(const guint *) v);
const guint64 *bits = v;
return (guint) ((*bits >> 32) ^ (*bits & 0xffffffffU));
}
/**
@ -2537,5 +2539,8 @@ g_double_equal (gconstpointer v1,
guint
g_double_hash (gconstpointer v)
{
return (guint) ((const guint) (*(guint64 *) v >> 32)) ^ (*(const guint *) v);
/* Same as g_int64_hash() */
const guint64 *bits = v;
return (guint) ((*bits >> 32) ^ (*bits & 0xffffffffU));
}