Skip to content

Commit 614530b

Browse files
Romain-Geissler-1Apcmoore
authored andcommitted
hash: fix strict aliasing UB in MurMur hash implementation
This was spotted when trying to upgrade the libseccomp fedora package to version 2.6.0 in fedora rawhide. It comes with gcc 15 and LTO enabled by default. When running the test 61-sim-transactions we get plenty of such errors in valgrind: ==265507== Use of uninitialised value of size 8 ==265507== at 0x4096AD: _hsh_add (gen_bpf.c:599) ==265507== by 0x40A557: UnknownInlinedFun (gen_bpf.c:2016) ==265507== by 0x40A557: gen_bpf_generate (gen_bpf.c:2341) ==265507== by 0x400CDE: UnknownInlinedFun (db.c:2685) ==265507== by 0x400CDE: UnknownInlinedFun (db.c:2682) ==265507== by 0x400CDE: UnknownInlinedFun (api.c:756) ==265507== by 0x400CDE: UnknownInlinedFun (util.c:162) ==265507== by 0x400CDE: UnknownInlinedFun (util.c:153) ==265507== by 0x400CDE: main (61-sim-transactions.c:128) ==265507== Uninitialised value was created by a stack allocation ==265507== at 0x409590: _hsh_add (gen_bpf.c:573) Investigating this a bit, it seems that because of LTO the MurMur hash implementation is being inlined in _hsh_add. The two buffers data and blocks to point at the same underlying data, but via incompatible type, which is a strict aliasing violation. Instead, remove the getblock32 function and inline the copy with memcpy. This is reproducible on a "fedora:rawhide" container (gcc 15) and using: export CFLAGS='-O2 -flto=auto -ffat-lto-objects -g' Signed-off-by: Romain Geissler <[email protected]> Reviewed-by: Sam James <[email protected]> Acked-by: Tom Hromatka <[email protected]> [PM: subject line tweak] Signed-off-by: Paul Moore <[email protected]>
1 parent 600b168 commit 614530b

File tree

1 file changed

+3
-9
lines changed

1 file changed

+3
-9
lines changed

src/hash.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,11 @@
1212
*/
1313

1414
#include <stdlib.h>
15+
#include <string.h>
1516
#include <inttypes.h>
1617

1718
#include "hash.h"
1819

19-
static inline uint32_t getblock32(const uint32_t *p, int i)
20-
{
21-
return p[i];
22-
}
23-
2420
static inline uint32_t rotl32(uint32_t x, int8_t r)
2521
{
2622
return (x << r) | (x >> (32 - r));
@@ -41,7 +37,6 @@ static inline uint32_t fmix32(uint32_t h)
4137
uint32_t hash(const void *key, size_t length)
4238
{
4339
const uint8_t *data = (const uint8_t *)key;
44-
const uint32_t *blocks;
4540
const uint8_t *tail;
4641
const int nblocks = length / 4;
4742
const uint32_t c1 = 0xcc9e2d51;
@@ -54,9 +49,8 @@ uint32_t hash(const void *key, size_t length)
5449
uint32_t h1 = 0;
5550

5651
/* body */
57-
blocks = (const uint32_t *)(data + nblocks * 4);
5852
for(i = -nblocks; i; i++) {
59-
k1 = getblock32(blocks, i);
53+
memcpy(&k1, data + (nblocks + i) * sizeof(uint32_t), sizeof(uint32_t));
6054

6155
k1 *= c1;
6256
k1 = rotl32(k1, 15);
@@ -68,7 +62,7 @@ uint32_t hash(const void *key, size_t length)
6862
}
6963

7064
/* tail */
71-
tail = (const uint8_t *)(data + nblocks * 4);
65+
tail = data + nblocks * sizeof(uint32_t);
7266
switch(length & 3) {
7367
case 3:
7468
k2 ^= tail[2] << 16;

0 commit comments

Comments
 (0)