Skip to content

Case 32 — Parameter Default Value Changes (C++)

Field Value
Verdict NO_CHANGE
Category No Change
Platforms Linux, macOS, Windows
Flags
Detected ChangeKinds
Source files browse on GitHub

Category: C++ Defaults | Verdict: 🟢 NO_CHANGE (binary ABI unchanged)

What changes

Method v1 signature v2 signature Effect
connect void connect(int timeout = 30) void connect(int timeout = 60) Default changed
configure void configure(bool verbose = true, int retries = 3) void configure(bool verbose, int retries = 5) verbose lost default; retries changed
disconnect void disconnect(int code) void disconnect(int code = 0) Default added

Why this is NOT a binary ABI break

In C++, default parameter values are resolved at the call site during compilation. When the compiler sees conn.connect(), it rewrites it to conn.connect(30) using the default from the header at compile time. The library's .so never knows about default values — it only receives the actual arguments.

This means:

  1. Default changed (timeout 30 -> 60): Binaries compiled against v1 will always pass 30. Only code recompiled against v2 will pass 60. No binary break.

  2. Default removed (verbose): Binaries compiled against v1 already have true baked in. Only recompilation against v2 would fail (source break) because configure() with zero args is no longer valid.

  3. Default added (disconnect): Existing binaries already pass explicit values. New code compiled against v2 can call disconnect() without arguments. Fully backward compatible.

The mangled symbol names are identical (_ZN10Connection7connectEi, etc.) because default values do not participate in name mangling.

Code diff

 class Connection {
 public:
-    void connect(int timeout = 30);
-    void configure(bool verbose = true, int retries = 3);
-    void disconnect(int code);
+    void connect(int timeout = 60);
+    void configure(bool verbose, int retries = 5);
+    void disconnect(int code = 0);
 };

Real Failure Demo

Severity: NONE (binary compatible)

Scenario: Compile app against v1 headers, swap in v2 .so.

# Build v1 library + app
g++ -shared -fPIC -g v1.cpp -o libfoo.so
g++ -g app.cpp -I. -L. -lfoo -Wl,-rpath,. -o app
./app
# → Parameter defaults demo (compiled against v1.hpp):
# →
# → Calling connect() with default timeout:
# →   Compiled as connect(30) from v1 header
# →   OK — v2 default is 60, but caller already passed 30
# →
# → Calling connect(45) with explicit timeout:
# →   OK — explicit args are unaffected
# →
# → Calling configure() with defaults:
# →   Compiled as configure(true, 3) from v1 header
# →   OK — v2 removed verbose default, but caller already passed true
# → ...

# Swap in v2 (no recompile)
g++ -shared -fPIC -g v2.cpp -o libfoo.so
./app
# → Output is IDENTICAL — defaults were baked into the caller at compile time.
# → The v2 library receives the same arguments as v1.

Source break verification (partial — configure() with no args fails):

# Create a minimal source that includes only v2.hpp and calls configure()
cat > /tmp/source_break.cpp << 'SRC'
#include "v2.hpp"
int main() {
    Connection conn;
    conn.configure();  // no args — v2 requires explicit 'verbose'
    return 0;
}
SRC
g++ -g /tmp/source_break.cpp -I. -L. -lfoo -Wl,-rpath,. -o /tmp/app_v2 2>&1
# → error: no matching function for call to 'Connection::configure()'
# → note: candidate expects 2 arguments, 0 provided
#    (because 'verbose' lost its default in v2)
rm -f /tmp/source_break.cpp /tmp/app_v2

Reproduce with abicheck

g++ -shared -fPIC -g v1.cpp -o libfoo_v1.so
g++ -shared -fPIC -g v2.cpp -o libfoo_v2.so
abidw --out-file v1.xml libfoo_v1.so
abidw --out-file v2.xml libfoo_v2.so
abidiff v1.xml v2.xml
echo "exit: $?"   # → 0 (no binary ABI change)

How to fix

No fix needed for binary compatibility. For source compatibility:

  • Do not remove defaults from public headers in minor releases.
  • If a default value must change, document it clearly — existing compiled binaries will silently continue using the old default until recompiled.
  • Consider using overloaded functions instead of defaults for critical parameters where behavioral differences matter.

References


Source files

See also: Examples overview · All NO_CHANGE cases · Category: No Change.