Case 170: Runtime Floor Raised (glibc Relink Drift)¶
| Field | Value |
|---|---|
| Verdict | π‘ COMPATIBLE_WITH_RISK |
| Category | Risk |
| Platforms | Linux, macOS, Windows |
| Flags | β |
Detected ChangeKinds |
runtime_floor_raised, symbol_version_required_added |
| Source files | examples/case170_env_runtime_floor_raised/ |
Category: Environment / Toolchain Drift | Verdict: π‘ COMPATIBLE_WITH_RISK
Verdict and consumer impact¶
libdemo.so.1 exports the exact same two functions (demo_init,
demo_process) in both versions β nothing about the declared interface
changed. But v2 was relinked on a newer distro, so its imports rebind to a
newer glibc version node: __libc_start_main moves from @GLIBC_2.28 to
@GLIBC_2.34. Existing consumers on a modern system are unaffected; the
same binary simply refuses to load (version 'GLIBC_2.34' not found) on
anything older than glibc 2.34 β RHEL 8, Ubuntu 20.04, and similar. Whether
that's a problem depends entirely on deployment targets abicheck can't see
on its own.
Old/new diff¶
There is no source change; this is a toolchain/build-environment diff between the two shipped binaries' dynamic version requirements:
| old.abi.json | new.abi.json |
|---|---|
__libc_start_main@GLIBC_2.28 (max glibc floor: 2.28) |
__libc_start_main@GLIBC_2.34 (max glibc floor: 2.34) |
abicheck command¶
abicheck compare old.abi.json new.abi.json # default
abicheck compare old.abi.json new.abi.json --env-matrix env-newer.yaml # declare floor >= 2.36
abicheck compare old.abi.json new.abi.json --env-matrix env-older.yaml # declare floor 2.28
Expected abicheck finding¶
Default (no --env-matrix):
Verdict: COMPATIBLE_WITH_RISK (exit 0)
- symbol_version_required_added: New symbol version requirement: GLIBC_2.34 (from libc.so.6)
- runtime_floor_raised: Runtime floor raised for libc.so.6: GLIBC_2.28 -> GLIBC_2.34
(required by: __libc_start_main@GLIBC_2.34)
--env-matrix env-newer.yaml (declared floor 2.36, e.g. Ubuntu 24.04+):
Verdict: COMPATIBLE (exit 0)
--env-matrix env-older.yaml (declared floor 2.28, e.g. RHEL 8):
Verdict: BREAKING (exit 4)
Minimum evidence¶
min_evidence: L0 β the ELF dynamic section's version-needed (verneed)
records list which symbol-version node each imported symbol requires; the
exported/imported symbol table alone (no debug info, no headers) is enough
to see the floor move.
Why abicheck catches it¶
abicheck reads each binary's verneed entries directly from L0 ELF
metadata and reports two granularities: the per-node fact
(symbol_version_required_added) and a roll-up
(runtime_floor_raised) that names the oldβnew deployment floor and the
importing symbol. The roll-up's evidence list is the actionable part β a
floor pulled up only by __libc_start_main (linked in by every binary) is
a pure relink artifact, while a real application-level symbol pulling the
floor up would mean the code genuinely started using a newer runtime API.
Real-world deployment scenario¶
This is what a CI job diffing two release builds of the same library
across a build-image upgrade sees β e.g. a package's builder migrating from
an older base image to a newer one (or a distro's compiler/glibc bump)
with zero source changes. The declared interface is untouched, but the
binary's minimum runtime silently rises, and only a build that pins (or
declares) its oldest supported runtime catches it before a customer on an
older system hits a load failure. --env-matrix is exactly that
declaration: pairing the observed floor against a stated deployment target
turns the open question into a pass/fail verdict, as the two --env-matrix
runs above show.
Safe redesign¶
Pin the build image (or use an old-sysroot/manylinux-style toolchain) so
released binaries target the oldest glibc you actually support, rather than
whatever the CI runner happens to ship. Where that's impractical, declare
the real deployment floor with --env-matrix so drift like this fails the
build intentionally instead of surfacing as a support ticket after release.
Cross-tool comparison¶
abidiff/abi-compliance-checker diff DWARF-carrying compiled binaries
for type/symbol changes; neither has a concept of a declared deployment
runtime floor or an --env-matrix-style target declaration, so there is no
equivalent reproduction of this finding with either tool.
Source files¶
env-newer.yamlenv-older.yamlnew.abi.jsonold.abi.json
See also: Examples overview Β· All COMPATIBLE_WITH_RISK cases Β· Category: Risk.