ASAN ODR violation false positives with AMD clang
- Dominant language
- C++
- Stars
- 25
- Forks
- 16
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
When running with AddressSanitizer enabled, AMD clang (tested with version 22, but version-independent) reports ODR (One Definition Rule) violations that do not appear with upstream clang (tested with versions 18 and 22).
## Observed Behavior
- **AMD clang**: Reports ODR violations under ASAN
- **Upstream clang 18**: No ODR violations reported
- **Upstream clang 22**: No ODR violations reported
## Example: False Positive on `types.h:51`
```
==938818==ERROR: AddressSanitizer: odr-violation (0x60d201042cb4):
[1] size=4 '.str' .../include/fusilli/attributes/types.h:51
[2] size=4 '.str' .../include/fusilli/attributes/types.h:51
These globals were registered at these points:
[1]:
#0 0x60d2011068e9 in __asan_register_globals /therock/src/compiler/amd-llvm/compiler-rt/lib/asan/asan_globals.cpp:447:3
#1 0x60d201107a49 in __asan_register_elf_globals /therock/src/compiler/amd-llvm/compiler-rt/lib/asan/asan_globals.cpp:430:3
#2 0x7511ef28d303 in call_init csu/../csu/libc-start.c:145:3
#3 0x7511ef28d303 in __libc_start_main csu/../csu/libc-start.c:347:5
#4 0x60d2010ed184 in _start (/home/srajeshk/claude-workspace/projects/fusilli/build/bin/samples/fusilli_pointwise_samples_pointwise_unary_ops+0x14b184)
[2]:
#0 0x60d2011068e9 in __asan_register_globals /therock/src/compiler/amd-llvm/compiler-rt/lib/asan/asan_globals.cpp:447:3
#1 0x60d201107a49 in __asan_register_elf_globals /therock/src/compiler/amd-llvm/compiler-rt/lib/asan/asan_globals.cpp:430:3
#2 0x7511ef28d303 in call_init csu/../csu/libc-start.c:145:3
#3 0x7511ef28d303 in __libc_start_main csu/../csu/libc-start.c:347:5
#4 0x60d2010ed184 in _start (/home/srajeshk/claude-workspace/projects/fusilli/build/bin/samples/fusilli_pointwise_samples_pointwise_unary_ops+0x14b184)
```
Both entries have the same size, same source location, and are in the same binary. The `.str` globals originate from string literals expanded by `FUSILLI_FORALL_DATA_TYPES` into a `static const std::unordered_map` at `types.h:47`:
```cpp
static const std::unordered_map kDataTypeToMlirTypeAsm =
{
#define DEFINE_ENUM(FUSILLI_TYPE, TORCH_TYPE, MLIR_TYPE) \
{DataType::FUSILLI_TYPE, MLIR_TYPE},
FUSILLI_FORALL_DATA_TYPES(DEFINE_ENUM)
#undef DEFINE_ENUM
};
```
Since this is a `static const` variable in a header, every TU that includes `types.h` gets its own copy — including the string literal globals. AMD's ASAN runtime registers each TU's copy separately and then flags the "duplicates" that are actually identical copies from the same source line.
## Root Cause Analysis
### Why This Is Not a Real ODR Violation
- **`static` at namespace scope = internal linkage.** Each TU gets its own independent, private copy. These are separate entities as far as the C++ standard is concerned.
- **The ODR governs entities with external linkage.** If two TUs define the same externally-linked symbol differently, that's a violation.
With `static const`, there is no "one definition" to violate because there is no shared entity. Each TU's copy is intentionally its own thing — this is the entire purpose of `static` at namespace scope. A real ODR violation would occur if the variable were declared without `static` or `inline` in a header.
### Why ASAN Flags It Anyway
ASAN's ODR checker registers globals at runtime and compares names and sizes. When it sees two globals with the same compiler-generated name (`.str`), it flags a conflict. It does not understand C++ linkage semantics — it conflates "two globals with the same name" with "ODR violation," when `static` linkage makes them distinct by design.
Additional factors that make AMD clang prone to these false positives:
1. **AMD-specific preprocessor defines** can change struct layouts across TUs, triggering the size-comparison heuristic.
2. **Fork divergence in codegen** — AMD's LLVM fork carries patches affecting global variable emission, symbol visibility, and template instantiation patterns.
3. **Different runtime libraries** — AMD's compiler-rt/libc++ may be built with different flags, introducing size mismatches in standard library globals.
4. **Fusilli is header-only with C++20** — heavy template instantiation and inline variables across TUs are a known source of spurious ODR reports.
## Workarounds
- Set `ASAN_OPTIONS=detect_odr_violation=0` to disable the ODR checker entirely
- Use `detect_odr_violation=1` instead of the default `2` — level 1 only flags size differences, while level 2 also flags type name differences
- Use upstream clang instead of AMD clang for ASAN CI runs to avoid the false positives
- Investigate specific flagged symbols to confirm they are not in user-defined types with conditional compilation paths
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.