Skip to content

Case 177: long double ABI Changed

Field Value
Verdict ๐Ÿ”ด BREAKING
Category Breaking
Platforms Linux
Flags ABI break
Detected ChangeKinds long_double_abi_changed
Source files examples/case177_long_double_abi_changed/

Category: Floating-Point ABI | Verdict: ๐Ÿ”ด BREAKING

Verdict and consumer impact

compute's name and purpose are unchanged โ€” "double the input" โ€” but v2's library was rebuilt to use IEEE 754 quad precision (__float128, from libquadmath) instead of the platform's native 80-bit x87 long double. Itanium mangles long double as e and __float128 as g, so the exported symbol name changes even though the C++ declaration still reads "compute": _Z7computee โ†’ _Z7computeg. Any binary linked against v1 resolves _Z7computee at link time; that symbol no longer exists in v2, so the dynamic linker refuses to load the app. Recompilation against v2 is mandatory.

Old/new diff

v1.hpp v2.hpp
long double compute(long double x); __float128 compute(__float128 x);

abicheck command

g++ -shared -fPIC -g v1.cpp -o libfoo_v1.so
g++ -shared -fPIC -g v2.cpp -o libfoo_v2.so -lquadmath
abicheck compare libfoo_v1.so libfoo_v2.so

Expected abicheck finding

Verdict: BREAKING (exit 4)

- func_removed: Public function removed: compute
  > Old binaries call a symbol that no longer exists; dynamic linker
    will refuse to load or crash at call site.
- long_double_abi_changed: long double ABI changed:
  compute(long double) -> compute(__float128) โ€” floating-point
  representation differs
  > The source signature is unchanged, but the floating-point format
    differs, so old binaries pass/return the value in the wrong size and
    bit layout.

Additions:
- func_added: New public function: compute(__float128)

Minimum evidence

min_evidence: L0 โ€” the exported-symbol table alone is enough: abicheck re-pairs the removed _Z7computee and added _Z7computeg symbols by their demangled signature, detecting the long-double-family type flip directly from the Itanium mangling token (e vs g). No debug info or headers needed; -g above is only there so the Runtime failure demonstration below can build a matching app.

Why abicheck catches it

A plain symbol diff would see this as an unrelated remove-and-add (_Z7computee gone, _Z7computeg new). abicheck's long_double_abi_changed detector instead re-pairs a removed/added symbol pair by demangled signature when they differ only in a long-double-family type, producing one finding that names the real transition โ€” a representation change, not a rename โ€” rather than two unrelated-looking symbol events.

Runtime failure demonstration

Severity: BREAKING / undefined symbol at load time

Scenario: compile app against v1, swap in v2 .so without recompile.

# Build old library + app
g++ -shared -fPIC -g v1.cpp -o libfoo.so
g++ -g app.cpp -I. -L. -lfoo -Wl,-rpath,. -o app
./app
# โ†’ compute(21.0) = 42.000000 (expected 42.0)

# Swap in new library (no recompile)
g++ -shared -fPIC -g v2.cpp -o libfoo.so -lquadmath
./app
# โ†’ ./app: symbol lookup error: ./app: undefined symbol: _Z7computee

Why BREAKING: the old app was linked against _Z7computee. v2's library exports _Z7computeg instead โ€” a different symbol, not a modified one โ€” so the dynamic linker refuses to resolve the reference at load time.

Safe redesign

Treat a long double-family representation change as a full ABI break, even when no C++ signature in the header text visibly changed spelling. Bump the library's SONAME when changing the underlying floating-point representation for any exported symbol. If both representations must be supported (e.g. during a ppc64 IEEE128 migration), ship both under distinct symbol versions rather than silently replacing one.

Real-world example: ppc64 toolchains moving long double from IBM double-double to IEEE binary128 hit exactly this transition โ€” every exported symbol taking or returning long double gets a new mangled name, forcing a full rebuild of dependents even though no C/C++ source changed spelling.

Cross-tool comparison

abidw --out-file v1.xml libfoo_v1.so
abidw --out-file v2.xml libfoo_v2.so
abidiff v1.xml v2.xml

abidiff/abidw are not installed in this environment, so no output is reproduced here.

References


Source files

  • CMakeLists.txt
  • app.cpp
  • v1.cpp
  • v1.hpp
  • v2.cpp
  • v2.hpp

See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.