Skip to content

Case 50: SONAME Inconsistent (Wrong Major Version)

Field Value
Verdict ๐ŸŸก COMPATIBLE_WITH_RISK
Category Risk
Platforms Linux
Flags Bad practice
Detected ChangeKinds โ€”
Source files examples/case50_soname_inconsistent/

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

  • CMakeLists.txt
  • app.c
  • bad.c
  • good.c

See also: Examples overview ยท All COMPATIBLE_WITH_RISK cases ยท Category: Risk.