Case 149: ODR Type Variant (Cross-Source, L4 Layout โ Layout)¶
| Field | Value |
|---|---|
| Verdict | ๐ API_BREAK |
| Category | API Break |
| Platforms | Linux |
| Flags | API break |
Detected ChangeKinds |
odr_type_variant |
| Source files | examples/case149_xcheck_odr_variant/ |
Category: API Break (Audit) | Verdict: ๐ API_BREAK
Verdict and consumer impact¶
Single-release audit: one build's evidence checked against itself, no
baseline comparison. abicheck's verdict is API_BREAK โ two translation
units materialize one public type, geometry::Vec3, with different
layouts (one TU's definition carries an extra member behind a macro the
other TU does not see). This is an ODR violation: the linker picks one
definition arbitrarily, and call sites compiled against the other TU's
layout read the wrong bytes at runtime. The shipped binary contains exactly
one layout, so nothing about the binary itself looks wrong โ the conflict
only exists in the relationship between the two TUs' own source-replayed
definitions.
What this snapshot contains¶
snapshot.abi.json is a single, hand-built AbiSnapshot carrying the L4
per-TU source-ABI replay for two translation units that both define
geometry::Vec3:
| Source in the snapshot | What it records |
|---|---|
Per-TU source-ABI surface (L4, build_source.source_abi per TU) |
TU-A's replayed geometry::Vec3 layout hash and TU-B's replayed geometry::Vec3 layout hash, and they differ |
abicheck command¶
Expected abicheck finding¶
Coverage
crosscheck:odr_type_variant present L4 per-TU type layouts: 1 type(s) with divergent cross-TU definitions (ODR conflict)
ABI-hygiene catalog (intra-version, advisory)
[warning] odr_type_variant: 1
Verdict: API_BREAK (exit 2)
Minimum evidence¶
min_evidence: L4 โ the shipped binary (L0/L1) and the header AST (L2)
each see exactly one geometry::Vec3 definition and look internally
consistent; only replaying each translation unit's own source (L4) and
comparing the per-TU layouts against each other exposes that two TUs
disagree about the same type's layout.
Why abicheck catches it¶
| Source | What it sees alone |
|---|---|
| Binary (L0/L1) | one geometry::Vec3 layout โ looks self-consistent |
| Header AST (L2) | one declaration โ looks self-consistent |
| Per-TU source-ABI replay (L4) | TU-A's Vec3 hash โ TU-B's Vec3 hash |
| Combination | the L4 surface records the per-TU conflict โ odr_type_variant (API_BREAK) |
odr_type_variant reads the L4 source-replay surface's recorded per-TU
type hashes, supplied by the source_index provider โ no single artifact
layer can see it, because the binary contains only the one layout the
linker happened to pick.
Why this matters for a real release¶
Whichever TU's definition the linker keeps, every call site compiled
against the other TU's assumed layout reads or writes the wrong offsets
for geometry::Vec3 โ silent corruption or misreads with no crash to flag
it. This is exactly the class of bug that is expensive to diagnose after
the fact (it reproduces only with specific link orders or optimization
levels) and cheap to catch here, before the build ships.
Safe redesign¶
Make the type's definition identical in every TU: guard the divergent member with the same macro everywhere and compile every TU with that macro consistently, or move the type to a single header all TUs include unconditionally so there is only ever one definition to replay.
Cross-tool comparison¶
odr_type_variant is a cross-source check unique to abicheck's audit mode
โ it compares two translation units' own replayed layouts for the same
type against each other, which isn't something abidiff/abi-compliance-checker
do (they diff two whole-binary ABI dumps against each other, not two TUs'
source-replayed definitions within one build).
Source files¶
snapshot.abi.json
See also: Examples overview ยท All API_BREAK cases ยท Category: API Break.