Skip to content

Case 50: SONAME Inconsistent (Wrong Major Version)

Field Value
Verdict ๐ŸŸข COMPATIBLE
Category Quality (Compatible)
Platforms Linux
Flags Bad practice
Detected ChangeKinds โ€”
Source files browse on GitHub

Policy verdict: ๐ŸŸก BAD PRACTICE | ABI compatibility verdict: COMPATIBLE

What this case is about

Both libraries export the same symbols with identical signatures. The difference is in the DT_SONAME metadata: v1 uses libfoo.so.0 while the project release version is 1.x (implying the correct SONAME should be libfoo.so.1).

This is a policy-level bad practice: the SONAME is present (unlike Case 05) but does not follow the convention of matching the ABI epoch / major version.

Why SONAME inconsistency is bad practice

  • Package managers (dpkg, rpm) use SONAME to generate dependency lists. A wrong SONAME major means packages depend on the wrong libfoo.so.0 and will fail to find libfoo.so.1 after a correct upgrade.
  • Parallel installation is broken: libfoo.so.0 and libfoo.so.1 are meant to coexist, but if the library was always libfoo.so.0, upgrading to the real ABI epoch 1 forces unnecessary coordinated rebuilds.
  • ldconfig creates symlinks based on SONAME. A stale SONAME means the wrong symlink tree, breaking runtime lookup for correctly-linked binaries.

What abicheck detects

  • SONAME_CHANGED: The SONAME differs between v1 and v2 (.so.0 vs .so.1). This is classified as a metadata change. Because the actual symbols and types are identical, the functional ABI is compatible.

Policy verdict: ๐ŸŸก BAD PRACTICE (SONAME mismatch is a packaging/upgrade hazard). ABI compatibility verdict: COMPATIBLE (same ABI surface; symbols and types identical).

How to reproduce

# Build both variants
gcc -shared -fPIC -g bad.c -o libbad.so -Wl,-soname,libfoo.so.0
gcc -shared -fPIC -g good.c -o libgood.so -Wl,-soname,libfoo.so.1

# Verify SONAME
readelf -d libbad.so  | grep SONAME
# โ†’ (SONAME) Library soname: [libfoo.so.0]  โ† wrong major
readelf -d libgood.so | grep SONAME
# โ†’ (SONAME) Library soname: [libfoo.so.1]  โ† correct

# Run abicheck
python3 -m abicheck.cli dump libbad.so  -o /tmp/v1.json
python3 -m abicheck.cli dump libgood.so -o /tmp/v2.json
python3 -m abicheck.cli compare /tmp/v1.json /tmp/v2.json
# โ†’ COMPATIBLE + SONAME_CHANGED note

How to fix

Set SONAME to match your project's ABI major version:

gcc -shared -fPIC lib.c -o libfoo.so.1.2.3 -Wl,-soname,libfoo.so.1
ln -sf libfoo.so.1.2.3 libfoo.so.1
ln -sf libfoo.so.1 libfoo.so

In CMake:

set_target_properties(foo PROPERTIES
    VERSION 1.2.3
    SOVERSION 1
)

Real Failure Demo

Severity: BAD PRACTICE

Scenario: app links against library with wrong SONAME, then we inspect DT_NEEDED.

# Build with wrong SONAME
gcc -shared -fPIC -g bad.c -o libfoo.so -Wl,-soname,libfoo.so.0
ln -sf libfoo.so libfoo.so.0   # create SONAME symlink so loader finds it
gcc -g app.c -L. -lfoo -Wl,-rpath,. -o app
readelf -d app | grep NEEDED
# โ†’ (NEEDED) Shared library: [libfoo.so.0]  โ† wrong major baked in
./app
# โ†’ foo() = 42, bar(5) = 6  (works today)

# After upgrade, libfoo.so.1 exists but app still looks for libfoo.so.0
# โ†’ runtime error: libfoo.so.0: cannot open shared object file

Why BAD PRACTICE: Runtime works today, but the wrong SONAME major gets baked into every consumer's DT_NEEDED. Future upgrades to the correct SONAME require rebuilding all consumers.

Real-world example

Debian's shared library policy requires SONAME to follow the libname.so.MAJOR convention. Packages with inconsistent SONAMEs are rejected during review because they break upgrade paths.

References


Source files

See also: Examples overview ยท All COMPATIBLE cases ยท Category: Quality (Compatible).