From de7abf54c7a602dc1f7905a9d5baffe59f58a607 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 21 Oct 2022 10:16:27 +0100 Subject: [PATCH] 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 --- glib/ghash.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/glib/ghash.c b/glib/ghash.c index 366c751ac..158779911 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -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)); }