Skip to content

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.yaml
  • env-older.yaml
  • new.abi.json
  • old.abi.json

See also: Examples overview Β· All COMPATIBLE_WITH_RISK cases Β· Category: Risk.