Case 143: Accidental Export (Single-Release Audit)¶
| Field | Value |
|---|---|
| Verdict | ๐ข COMPATIBLE |
| Category | Quality (Compatible) |
| Platforms | Linux |
| Flags | Bad practice |
Detected ChangeKinds |
exported_not_public |
| Source files | examples/case143_audit_accidental_export/ |
Category: Quality (Audit) | Verdict: ๐ข COMPATIBLE (bad practice)
Verdict and consumer impact¶
This is a single-release audit (ADR-035 "G20" corpus): there is no v1/v2
pair to diff, just one build's evidence checked against itself. abicheck's
verdict is COMPATIBLE โ nothing here is a break today โ but the audit flags
an advisory ABI-hygiene finding: debug_dump() ships with default ELF
visibility (so it's in the dynamic symbol table, and any consumer can dlsym
or link against it) yet it is never declared in a public header. Whoever
maintains this library believes debug_dump() is private and free to change
or remove at will; in reality it's already load-bearing ABI for anyone who
found it in nm -D libdemo.so. The fix belongs in this release, not after
a consumer files a breakage report against a "private" function.
What this snapshot contains¶
snapshot.abi.json is a single, hand-built AbiSnapshot (via
scripts/gen_g20_fixtures.py) representing one build of libdemo.so, with
both its ELF export table and its public-header AST baked in:
| Source in the snapshot | What it records |
|---|---|
Binary export table (L0, elf.symbols) |
_Z6renderv (render), _Z11debug_dumpv (debug_dump) โ both exported with default visibility |
Public-header AST (L2, functions[].origin) |
render has origin: public_header; debug_dump has origin: export_only โ it was found in the binary but never declared in any header abicheck was pointed at |
abicheck command¶
Expected abicheck finding¶
Verdict: COMPATIBLE (exit 0)
crosscheck:exported_not_public present binary exports โ public headers: 1 of 2
export(s) undocumented (1 accounted as documented API / compiler artifact);
by reason: undeclared_export=1
ABI-hygiene catalog (intra-version, advisory)
[warning] exported_not_public: 1
Minimum evidence¶
min_evidence: L2 โ the binary export table alone (L0) cannot distinguish an
intentional export from an accidental one; the public-header AST (L2) is what
supplies the "documented API" side of the comparison. Only the combination of
the two lets abicheck tell them apart.
Why abicheck catches it¶
exported_not_public is a cross-source check, not a plain diff: abicheck
reconciles the ELF dynamic-symbol table against the set of declarations
reachable from the public headers it was pointed at (binary_exports and
public_header_ast, per provider_assertions). A symbol present in one set
and absent from the other is what makes the finding โ neither source alone
can see it, since the export table has no notion of "public" and the header
AST has no notion of "actually shipped in this binary."
Why this matters for a real release¶
An accidental export looks free to change because nothing declares it โ
until a downstream consumer discovers it via nm/dlsym, starts depending
on it, and a later "just delete this internal helper" cleanup turns into a
real func_removed break for that consumer. Catching it at audit time, on
the release that introduced it, is strictly cheaper than catching it after
someone downstream has already linked against it.
Safe redesign¶
Either mark the symbol hidden so it never reaches the export table
(__attribute__((visibility("hidden"))), or add it to the version script's
local: block), or, if it's genuinely meant to be public, declare it in an
installed header so the audit no longer flags it and the contract is
explicit.
Cross-tool comparison¶
exported_not_public is a cross-source check unique to abicheck's audit
mode โ it reconciles two artifacts of the same build (export table vs.
public-header AST) rather than diffing two releases, which is outside what
abidiff/abi-compliance-checker do (they compare two ABI dumps against
each other, not a binary against its own headers).
Source files¶
snapshot.abi.json
See also: Examples overview ยท All COMPATIBLE cases ยท Category: Quality (Compatible).