Skip to content

Case 21 — Method Became Static

Field Value
Verdict 🔴 BREAKING
Category Breaking
Platforms Linux
Flags ABI break, API break
Detected ChangeKinds func_static_changed
Source files browse on GitHub

Verdict: 🔴 BREAKING (calling convention contract)

What changes

Version Declaration
v1 class Widget { int value; int bar(); };
v2 class Widget { static int bar(); };

Why this is ABI-breaking

For Itanium C++ ABI, static-ness is not encoded in symbol mangling for this case, so the symbol still resolves (_ZN6Widget3barEv).

But call contract changes: - v1 call site passes implicit this - v2 static function expects no this

So old binaries can still link, yet execute with a mismatched calling convention.

Real Failure Demo

Severity: CRITICAL

This demo shows a deterministic wrong result (not only “possible UB”): - v1 behavior: returns value + 1 - app sets value=41, expects 42 - v2 static method returns fixed 7

# Build v1 + app (compiled against old header)
g++ -shared -fPIC -g old/lib.cpp -Iold -o libwidget.so
g++ -g app.cpp -Iold -L. -lwidget -Wl,-rpath,. -o app
./app
# expected:
# bar() called (instance method), value=41
# got=42 expected=42

# Swap in v2 (method became static, same symbol still links)
g++ -shared -fPIC -g new/lib.cpp -Inew -o libwidget.so
./app
# expected:
# bar() called (static method), returning fixed value
# got=7 expected=42
# WRONG RESULT: method call contract changed (instance -> static)

Why this case matters

This is a silent binary-compat trap: loader/linker are happy, but runtime semantics are broken. No crash is required to prove ABI break — wrong results are enough.


Source files

See also: Examples overview · All BREAKING cases · Category: Breaking.