arm64 + ASan: clang miscompiles preserve_none continuation chains (2,727 CI test failures) #38

Open
opened 2026-06-12 20:16:39 +00:00 by andrew · 0 comments
Owner

All `conflict_set_fuzz_*` failures on arm64 in CI (2,340 SEGVs in `interleavedWrites`, 387 in `check`) are caused by a clang codegen bug on aarch64, not by a bug in this codebase.

Evidence

All built from identical source and flags, running the fuzz corpus:

Configuration Result
aarch64, clang 20.1.8 / 21.1.8 / trunk 22.1.7, ASan, `preserve_none` ~97% of corpus inputs SEGV
same, but UBSan-only or no sanitizer clean
same, but `PRESERVE_NONE` defined empty (musttail + interleaved path still enabled) clean (0/1000, 0/300)
x86-64, clang 21, ASan, `preserve_none` clean (CI run #9)

The crash is `interleavedWrites` resuming after the `inProgress->continuation(...)` call and loading a nulled pointer from its own frame (SEGV reading address 0x8 = `entry.rangeVersion` offset of a null `Node*`), i.e. the `preserve_none` callee chain corrupts caller state that ASan's instrumentation rearranged. Adding/removing an ABI attribute must not change observable behavior of correct C++, so this is a compiler bug.

Action item

Minimize and file an LLVM bug (https://github.com/llvm/llvm-project/issues). Note: a naive small musttail+preserve_none+ASan state machine does NOT reproduce; minimization from ConflictSet.cpp (creduce or manual) is needed. Reproduces on any aarch64 host with:

clang++ -DENABLE_FUZZ -Iinclude -isystem third_party/valgrind -DNVALGRIND -O3 \
  -std=gnu++20 -fPIC -g -mbranch-protection=standard -UNDEBUG \
  -fsanitize=address ConflictSet.cpp FuzzTestDriver.cpp -o fuzz_driver
./fuzz_driver corpus/008e3be49d62c3e7fa3785b882bdb65ee4b68977

Workaround

Disable `preserve_none` when building with ASan on aarch64 (keeps it in production builds and in x86-64 ASan CI coverage).

All \`conflict_set_fuzz_*\` failures on arm64 in CI (2,340 SEGVs in \`interleavedWrites\`, 387 in \`check\`) are caused by a clang codegen bug on aarch64, not by a bug in this codebase. ## Evidence All built from identical source and flags, running the fuzz corpus: | Configuration | Result | |---|---| | aarch64, clang 20.1.8 / 21.1.8 / trunk 22.1.7, ASan, \`preserve_none\` | ~97% of corpus inputs SEGV | | same, but UBSan-only or no sanitizer | clean | | same, but \`PRESERVE_NONE\` defined empty (musttail + interleaved path still enabled) | clean (0/1000, 0/300) | | x86-64, clang 21, ASan, \`preserve_none\` | clean (CI run #9) | The crash is \`interleavedWrites\` resuming after the \`inProgress->continuation(...)\` call and loading a nulled pointer from its own frame (SEGV reading address 0x8 = \`entry.rangeVersion\` offset of a null \`Node*\`), i.e. the \`preserve_none\` callee chain corrupts caller state that ASan's instrumentation rearranged. Adding/removing an ABI attribute must not change observable behavior of correct C++, so this is a compiler bug. ## Action item Minimize and file an LLVM bug (https://github.com/llvm/llvm-project/issues). Note: a naive small musttail+preserve_none+ASan state machine does NOT reproduce; minimization from ConflictSet.cpp (creduce or manual) is needed. Reproduces on any aarch64 host with: clang++ -DENABLE_FUZZ -Iinclude -isystem third_party/valgrind -DNVALGRIND -O3 \ -std=gnu++20 -fPIC -g -mbranch-protection=standard -UNDEBUG \ -fsanitize=address ConflictSet.cpp FuzzTestDriver.cpp -o fuzz_driver ./fuzz_driver corpus/008e3be49d62c3e7fa3785b882bdb65ee4b68977 ## Workaround Disable \`preserve_none\` when building with ASan on aarch64 (keeps it in production builds and in x86-64 ASan CI coverage).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weaselab/conflict-set#38