Cyan4973 / Cyan4973/xxHash

gcc 16 arch x86-64 v3 miscompilation due to aliasing

Closed
#1,126 0 comments 2 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.