Skip to content

Case 148: Header Build-Context Mismatch (Cross-Source Flagship)

Field Value
Verdict 🟠 API_BREAK
Category API Break
Classification Scenario — Capability / evidence demonstration · audit
Platforms Linux
Flags API break
Detected ChangeKinds header_build_context_mismatch
Source files catalog/cases/case148_xcheck_header_build_mismatch/
Related rules header-build-context-mismatch
Subject Export/declaration mismatches

Category: API Break (Audit) | Verdict: 🟠 API_BREAK

Verdict and consumer impact

Single-release audit: one build's evidence checked against itself, no baseline comparison. This finding's own kind is classified API_BREAK (the severity ground-truth row above); the audit itself reports no compatibility verdict and, by default, exits 0 — an audit has no baseline to break against, so it never emits 2/4, the compatibility family's own break codes. Gating on a hygiene finding like this one is opt-in via the orthogonal audit-gate axis : adding --severity-preset default (or strict) reproduces legacy scan's gating decision on this exact finding, but through its own exit code 3, never 2, so a hygiene gate can't be mistaken for a real compatibility break — measured live: abicheck compare --no-baseline snapshot.abi.json exits 0, abicheck compare --no-baseline snapshot.abi.json --severity-preset default exits 3. The finding: the public headers were parsed without the build's actual ABI-relevant flags (glibcxx_use_cxx11_abi, -DBIG_BUFFERS), so the layout a context-free header parse reports is not the layout the shipped binary actually has. A consumer who compiles against these headers with the project's documented build flags gets a different struct layout than the header-only view implied — silently, with no compiler warning, because nothing in the header text or the binary alone says the parse context was wrong. Only cross-checking the header's macro context against the build's real compile flags surfaces the divergence.

What this snapshot contains

snapshot.abi.json is a single, hand-built AbiSnapshot for one build of libdemo.so, carrying both the header-derived layout and the build's actual compile context:

Source in the snapshot What it records
Public-header AST (L2, context-free parse) a layout parsed without -DBIG_BUFFERS and without the project's glibcxx_use_cxx11_abi setting — reported with full confidence, and wrong
Build config (L3, build_source.build_config / compile flags) the project actually compiles this TU with -DBIG_BUFFERS=1 and a pinned glibcxx_use_cxx11_abi value

abicheck command

abicheck compare --no-baseline snapshot.abi.json

compare --no-baseline, not scan

0.6 makes this the declared spelling for a single-build audit, and retires scan. This case was blocked on that migration until 2026-09-09; the audit now reports the finding below directly, and tests/parity/test_no_baseline_audit_corpus_parity.py pins that it reports at least every check scan does, counted per finding kind, while manufacturing no comparison of its own (no verdict, no changes[] entry).

Expected abicheck finding

# ABI audit: libdemo.so (no baseline)

OLD side: **declared absent** (`--no-baseline`) -- this is an audit of the candidate build alone, not a compatibility comparison. No additions, removals, or compatibility verdict are reported.

- Candidate version: `1.0`
- Acquisition state (OLD): `declared_absent`
- Evidence tiers: header

## Candidate-side findings

| Finding | Symbol | Severity | State | Detail |
| --- | --- | --- | --- | --- |
| `header_build_context_mismatch` | `-` | potential_breaking | present in this build | Public headers were parsed without the build's ABI-relevant context: the build records 2 ABI-affecting flag(s) (define:BIG_BUFFERS, glibcxx_use_cxx11_abi) but the header AST was captured context-free, so the declared API surface may not match the shipped translation units. Re-dump the headers with the build's compile_commands.json. |

Minimum evidence

min_evidence: L3 — the L2 header-AST layout alone is reported with full confidence and no signal that anything is wrong; only the L3 build config's actual compile flags give abicheck something to cross-check the L2 macro context against. Without L3 evidence the check is skipped outright (as seen on cases that lack it, e.g. case149's coverage line for this same check), never a false clean.

Why abicheck catches it

Source What it sees alone
Binary (L0/L1) a valid layout — blind to which macros produced it
Header AST (L2) a layout parsed without -DBIG_BUFFERS → the wrong layout, reported with full confidence
Build flags (L3) the project compiled the TU with -DBIG_BUFFERS=1
Combination L2 macros ↔ L3 flags disagree → header_build_context_mismatch (API_BREAK)

header_build_context_mismatch is a cross-source check: abicheck compares the macro/flag context the header AST was parsed under against the build system's actual compile flags for that translation unit. Neither source alone carries both halves of the fact — the header parse doesn't know what the build actually used, and the build flags alone don't know what the header parse assumed.

Why this matters for a real release

A context-free header parse is the common case for any ABI tool run without build integration — most CI pipelines run the header scan once, separately from the actual build. If that scan silently reports a layout that disagrees with what the compiler produces, every downstream layout-based finding (struct sizes, member offsets, vtable slots) inherits the error with full confidence and no warning. Catching the mismatch here means the project fixes its scan invocation (or its build) before a consumer trusts a wrong layout report.

Safe redesign

Parse the public headers with the same ABI-relevant flags the build uses — feed abicheck the project's compile database (--sources/--build-info) so the header AST is built under the real macro context, instead of a bare -H include/ pass with no build integration.

Cross-tool comparison

header_build_context_mismatch is a cross-source check unique to abicheck's audit mode — it reconciles the macro context a header parse assumed against the build system's actual compile flags for the same translation unit, which isn't something abidiff/abi-compliance-checker do (they diff two ABI dumps against each other, not a single build's header parse against its own build config).


Source files

  • snapshot.abi.json

See also: Compatibility Catalog · All API_BREAK cases · Category: API Break · Subject: Export/declaration mismatches.