gcc 16 arch x86-64 v3 miscompilation due to aliasing
- Dominant language
- C
- Stars
- 11.2k
- Forks
- 913
- Avg merge
- 2h 57m
- Merged PRs (30d)
- 17
Description
[xxh_aliasing_repro.tar.gz](https://github.com/user-attachments/files/31349394/xxh_aliasing_repro.tar.gz)
Happens on openzl code. What it shows
The bug is in src/openzl/shared/xxhash.h: with XXH_FORCE_MEMORY_ACCESS == 1 (the default for GCC), XXH_read32/XXH_read64 read through a __attribute__((__aligned__(1))) typedef. That attribute lowers alignment but grants no
__may_alias__, so the access is still a uint32_t/uint64_t lvalue. Reading memory whose effective type is something else (a float/double written through a sibling pointer) is UB under C 6.5p7, and GCC's TBAA is allowed to assume
the store doesn't alias the load and hoist the load out of the loop — exactly the "code hoisting in MyMap_insert" you described.
Reproduction (gcc-16, -O2 -march=x86-64-v3)
XXH_read32 : hoisted(aliased)=0000000000000000 correct(memcpy)=00000010420b0000 *** MISMATCH (load hoisted) ***
XXH_read64 : hoisted(aliased)=0000000000000000 correct(memcpy)=d041600000000000 *** MISMATCH (load hoisted) ***
The generated code confirms the hoist:
MyMap_insert_u32:
movl (%rdi), %eax # load *key_slot ONCE, before the loop
movl $0x42bd0000,(%rsi) # store final float
salq $6, %rax # acc = pre-loop value * ITERS
ret
It reproduces at -O2/-O3, with and without -march=x86-64-v3 — the driver is TBAA + loop-invariant motion, v3 is just your trigger.
Files (in xxh_repro/, also as xxh_aliasing_repro.tar.gz)
- repro.c — verbatim xxHash read helpers (UB form) + memcpy reference + __may_alias__ source-fix variant; four noinline,noclone MyMap_insert_* loops compared.
- run.sh — builds buggy (-O2 -march=x86-64-v3) and fixed (-fno-strict-aliasing) and prints both.
- README.md — symptom, root cause, generated code, fixes, toolchain.
Fixes (all demonstrated in the reproducer)
- Source (preferred): add __may_alias__ to the typedefs in XXH_read32/XXH_read64 — the may_alias-fix rows are correct even under strict aliasing. This mirrors what xxHash already does for NEON via XXH_ALIASING.
- Build flag: -fno-strict-aliasing (works, broader perf cost).
- Config: set XXH_FORCE_MEMORY_ACCESS=0 (memcpy-based reads, the documented safe path).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with src/openzl/shared/xxhash.h, then run xxh_repro/run.sh and read xxh_repro/README.md to compare the GCC strict-aliasing results with the memcpy and may_alias variants. Done means the reproduced XXH_read32 and XXH_read64 cases no longer show a mismatch under the documented build settings and the relevant tests pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100