Case 53: Namespace Pollution (Generic Symbol Names)¶
| Field | Value |
|---|---|
| Verdict | ๐ด BREAKING |
| Category | Breaking |
| Platforms | Linux |
| Flags | ABI break, API break, Bad practice |
Detected ChangeKinds |
func_removed, func_added |
| Source files | examples/case53_namespace_pollution/ |
Category: API Design | Verdict: ๐ด BREAKING (bad practice)
Verdict and consumer impact¶
v1 exports functions with extremely generic names: init, process,
cleanup, status. v2 renames them to mylib_init, mylib_process,
mylib_cleanup, mylib_status with a proper library prefix. The rename
itself is a hard ABI break โ every consumer that resolved the old,
unprefixed names fails to load against v2 โ but the underlying problem is
that v1's names were a collision time-bomb in the first place: C has no
namespaces, and any other library sharing the process that also exports
init/process/cleanup/status would silently interpose or be
interposed on.
Old/new diff¶
| bad.c (v1) | good.c (v2) |
|---|---|
int init(void) |
int mylib_init(void) |
int process(int data) |
int mylib_process(int data) |
void cleanup(void) |
void mylib_cleanup(void) |
int status(void) |
int mylib_status(void) |
abicheck command¶
gcc -shared -fPIC -g bad.c -o libfoo_v1.so
gcc -shared -fPIC -g good.c -o libfoo_v2.so
abicheck compare libfoo_v1.so libfoo_v2.so
Expected abicheck finding¶
Verdict: BREAKING (exit 4)
- func_removed: Public function removed: status
- func_removed: Public function removed: cleanup
- func_removed: Public function removed: process
- func_removed: Public function removed: init
> Old binaries call a symbol that no longer exists; dynamic linker
will refuse to load or crash at call site.
- symbol_renamed_batch: Batch symbol rename detected (namespace
refactoring): prefix 'mylib_' added to 4 symbols (cleanup ->
mylib_cleanup, init -> mylib_init, process -> mylib_process, status ->
mylib_status)
> Multiple symbols renamed (e.g. namespace prefix added/removed); old
binaries reference the old names and will get undefined symbol errors
at load time.
Additions:
- func_added: New public function: mylib_status, mylib_cleanup,
mylib_process, mylib_init
Minimum evidence¶
min_evidence: L0 โ the exported-symbol table alone shows four names
disappearing and four new ones appearing; abicheck's symbol_renamed_batch
heuristic further correlates the two sets by common prefix, all from the
.dynsym table with no debug info or headers needed.
Why abicheck catches it¶
The dynamic symbol table is authoritative L0 evidence โ abicheck diffs the
exported-symbol sets directly. Beyond the plain func_removed/func_added
pairs, abicheck's rename-detection heuristic notices that all four removed
names reappear with a shared mylib_ prefix and groups them into a single
symbol_renamed_batch finding, flagging it as a namespace-prefixing
refactor rather than four unrelated symbol changes.
Runtime failure demonstration¶
Severity: BREAKING
Scenario: compile app against v1's unprefixed API, swap in v2 .so
without recompile.
# Build old library + app
gcc -shared -fPIC -g bad.c -o libfoo.so
gcc -g app.c -L. -lfoo -Wl,-rpath,. -o app
./app
# โ status() = 1
# โ process(21) = 43
# โ status() = 0
# Swap in new library (no recompile)
gcc -shared -fPIC -g good.c -o libfoo.so
./app
# โ ./app: symbol lookup error: ./app: undefined symbol: process
Why BREAKING: all four of v1's exported names are gone from v2's dynamic
symbol table; the runtime linker cannot resolve them and the process fails
before main() runs.
Safe redesign¶
Use a consistent prefix for all exported symbols from the start:
/* Good: all symbols prefixed with library name */
int mylib_init(void);
int mylib_process(int data);
void mylib_cleanup(void);
Or use a version script to hide any unprefixed internal names:
Real-world example: zlib uses a z_/inflate/deflate naming
convention, OpenSSL uses SSL_/EVP_/BN_ prefixes, SQLite prefixes
everything with sqlite3_, and libpng uses png_ โ all specifically to
avoid the flat-namespace collision this case demonstrates. Libraries that
historically did not prefix (early POSIX open, read, write) cause
endless compatibility headaches.
Cross-tool comparison¶
References¶
Source files¶
CMakeLists.txtapp.cbad.cgood.c
See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.