Case 98: C++ Standard Floor Raised¶
| Field | Value |
|---|---|
| Verdict | ๐ก COMPATIBLE_WITH_RISK |
| Category | Risk |
| Platforms | Linux, macOS, Windows |
| Flags | โ |
Detected ChangeKinds |
abi_relevant_build_flag_changed |
| Source files | examples/case98_cxx_standard_floor_raised/ |
Category: Build context risk | Verdict: โ ๏ธ COMPATIBLE_WITH_RISK
Verdict and consumer impact¶
v1.h/v2.h declare an identical public surface, and neither uses any
post-C++17 construct โ a consumer TU including either header compiles
unchanged. What changes is the library's own build contract: v1 is
built with -std=gnu++17, v2 with -std=c++20. The binary ABI (symbols,
layout, vtables) is untouched, so nothing breaks today โ but the producer
now assumes a newer C++ dialect than before, and that's a deployment risk
signal worth surfacing before it turns into a real break (e.g. once the
library starts relying on standard-library types whose layout differs
across dialects).
Old/new diff¶
| v1.h / v1.cpp | v2.h / v2.cpp |
|---|---|
| Declarations byte-identical to v2 | Declarations byte-identical to v1 |
Built with -std=gnu++17 |
Built with -std=c++20 (V2_COMPILE_OPTIONS in CMakeLists.txt) |
abicheck command¶
g++ -std=gnu++17 -shared -fPIC -g v1.cpp -o old/liblib_v1.so
g++ -std=c++20 -shared -fPIC -g v2.cpp -o new/liblib_v2.so
# compile_commands.json per side records the -std flag actually used
abicheck compare old/liblib_v1.so new/liblib_v2.so \
--depth build \
--build-info old=old/compile_commands.json \
--build-info new=new/compile_commands.json
Expected abicheck finding¶
Verdict: COMPATIBLE_WITH_RISK (exit 0)
## Deployment Risk Changes
- abi_relevant_build_flag_changed: Build option 'std:CXX' changed: 'gnu++17' -> 'c++20'
Minimum evidence¶
min_evidence: L3 โ the symbol set, layout, and header-declared surface
are all byte-identical between v1 and v2, so an L0โL2 artifact-only scan
returns NO_CHANGE: that's a documented false negative from insufficient
evidence, not an alternative valid verdict. Only L3 build-context
comparison (a compile database recording each side's -std= flag) carries
the fact abicheck needs here. L4/L5 source replay is not required.
Why abicheck catches it¶
With --depth build and a --build-info compile database per side,
abicheck's build-context collector reads each compile unit's flags and
records std:CXX. Comparing the two sides' recorded standards directly
surfaces the gnu++17 โ c++20 change as abi_relevant_build_flag_changed,
independent of whether the flag change produced any observable binary
difference yet.
Runtime failure demonstration¶
This case is COMPATIBLE_WITH_RISK, not a hard break โ there is no crash
to demonstrate. Verified directly: the consumer app compiles unchanged
against either header and behaves identically whether linked against
liblib_v1.so or hot-swapped to liblib_v2.so (no recompile):
g++ -std=c++17 app.cpp -Iold -Lold -llib_v1 -Wl,-rpath,old -o app
./app # โ 42
# swap in the v2 .so (no recompile)
cp new/liblib_v2.so old/liblib_v1.so
./app # โ 42 (identical output)
No observable effect on existing binaries โ the risk is in what the raised standard floor licenses the library to do next, not in today's ABI.
Safe redesign¶
Track and publish the minimum/maximum supported C++ standard as part of
the library's documented ABI contract, and treat a floor change as a
notable release-note item even when it produces no symbol/layout diff
today. If the library exposes any STL types across the ABI boundary
(std::string, std::vector, โฆ), pin the standard library's ABI mode
explicitly (see case 104) rather than letting the compiler default drift
between builds.
Real-world example: projects that bump CMAKE_CXX_STANDARD in a
"modernization" PR often don't realize the new floor is itself an
ABI-relevant fact for consumers cross-compiling or vendoring the library
under a pinned older toolchain โ the break shows up later as a confusing
toolchain-compatibility bug, not at review time.
Cross-tool comparison¶
abidiff/abi-compliance-checker compare binary artifacts (with optional
DWARF) and have no concept of "build context" outside the binary itself;
neither would report anything for this case, since the .so files are
layout-identical. Detecting a build-flag drift like this requires
consuming the compile database directly, which is what abicheck's L3
build-context layer is for.
References¶
Source files¶
CMakeLists.txtapp.cppv1.cppv1.hv2.cppv2.h
See also: Examples overview ยท All COMPATIBLE_WITH_RISK cases ยท Category: Risk.