Skip to content

Case 43: Base Class Member Added

Field Value
Verdict ๐Ÿ”ด BREAKING
Category Breaking
Platforms Linux, macOS, Windows
Flags ABI break, API break
Detected ChangeKinds โ€”
Source files browse on GitHub

Category: C++ Layout | Verdict: ๐Ÿ”ด BREAKING

What breaks

A data member is added to a base class (Base). This shifts the memory layout of all derived classes โ€” their fields move to higher offsets. Any consumer binary compiled against v1 headers will read Derived::value at the wrong offset when linked against the v2 library, causing silent data corruption or crashes.

Why abidiff catches it

abidiff reports Added_Base_Class_Data_Member and exits with code 4 (ABI change). Note: abidiff exits 4 (not 12) because this is a layout change, not a symbol removal. abicheck detects: TYPE_SIZE_CHANGED on Base, TYPE_FIELD_OFFSET_CHANGED on Derived::value.

Code diff

v1.hpp v2.hpp
class Base { int base_id; ... }; class Base { int base_id; int extra_field; ... };
class Derived : public Base { int value; }; class Derived : public Base { int value; };
sizeof(Derived)=16, Derived::value @ offset 12 sizeof(Derived)=24, Derived::value shifts to offset 16 (+4 bytes)

Real Failure Demo

Severity: ๐Ÿ”ด CRITICAL

Scenario: compile app against v1, swap in v2 .so โ€” Derived::value is read at wrong offset.

# Build libraries
g++ -shared -fPIC -g v1.cpp -o libv1.so
g++ -shared -fPIC -g v2.cpp -o libv2.so

# The base-class size shift is visible to abidiff:
abidw --out-file v1.abi libv1.so
abidw --out-file v2.abi libv2.so
abidiff v1.abi v2.abi
echo "exit: $?"   # โ†’ 4 (ABI change: base class data member added)

Reproduce manually

g++ -shared -fPIC -g v1.cpp -o libv1.so
g++ -shared -fPIC -g v2.cpp -o libv2.so
abidw --headers-dir . --out-file v1.abi libv1.so
abidw --headers-dir . --out-file v2.abi libv2.so
abidiff v1.abi v2.abi
echo "exit: $?"   # โ†’ 4

How to fix

Never add data members to a base class that has derived classes in the public API. Options: 1. Pimpl on Base โ€” put the new field in a private Impl* struct. 2. SONAME bump โ€” major version bump + abi_tag if breaking change is unavoidable. 3. Add to Derived, not Base โ€” if only one derived class needs the field.


Source files

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