case143 — Accidental export (single-release audit)¶
| Field | Value |
|---|---|
| Verdict | 🟡 COMPATIBLE_WITH_RISK |
| Category | Risk |
| Platforms | Linux |
| Flags | Bad practice |
Detected ChangeKinds |
— |
| Source files | examples/case143_audit_accidental_export/ |
Verdict: 🟡 COMPATIBLE_WITH_RISK · Cross-check: exported_not_public ·
Mode: single-release audit (no baseline) · Evidence tier: L2
What it demonstrates¶
A function compiled with default visibility but never declared in a public header is an accidental export: it ships in the dynamic symbol table, so consumers can bind to it, yet it is not part of the documented API. abicheck finds this from one artifact, with no previous release to diff against.
Why no single source sees it¶
| Source | What it sees alone |
|---|---|
| Binary export table (L0) | _Z6renderv, _Z11debug_dumpv — both look like ordinary exports |
| Public-header AST (L2) | declares only render() |
| Combination | debug_dump() is exported but undeclared → EXPORTED_NOT_PUBLIC |
The cross-check needs both the binary exports and the public-header decls; neither in isolation can tell an accidental export from an intentional one.
Reproduce¶
The committed snapshot.abi.json carries the same L0 + L2 provenance a live
scan --audit would dump, so tests/test_g20_catalog.py validates the finding
compiler-free.
Fix¶
Add debug_dump to the version script's local block (or mark it
__attribute__((visibility("hidden")))) — or, if it is meant to be public,
declare it in an installed header.
Source files¶
snapshot.abi.json
See also: Examples overview · All COMPATIBLE_WITH_RISK cases · Category: Risk.