Case 213: Calling Convention via a Function-Like Macro¶
| Field | Value |
|---|---|
| Verdict | 🔴 BREAKING |
| Category | Breaking |
| Classification | Rule |
| Platforms | Linux |
| Flags | ABI break |
Detected ChangeKinds |
calling_convention_changed |
| Source files | catalog/cases/case213_calling_convention_function_like_macro_changed/ |
| Rule family | calling-convention-function-like-macro-changed |
| Subject | Calling convention and integer-model changes |
Category: Calling Convention | Verdict: 🔴 BREAKING
Verdict and consumer impact¶
vector_dot is declared double MATHLIB_CC(cc) vector_dot(...) with
#define MATHLIB_CC(cc) __attribute__((cc)). Only the macro argument changes,
from sysv_abi in v1 to ms_abi in v2, which moves the arguments to other
registers. An unchanged old consumer computes a wrong result.
Before the 2026-10-11 re-audit fix, the CastXML lane skipped function-like
macros entirely (NO_CHANGE). The Clang lane reported the break, but also a
spurious func_return_changed, because clang prints the macro invocation
(MATHLIB_CC(ms_abi) double (...)) into the function's type spelling.
Old/new diff¶
| v1.h | v2.h |
|---|---|
double MATHLIB_CC(sysv_abi) vector_dot(...); |
double MATHLIB_CC(ms_abi) vector_dot(...); |
abicheck command¶
gcc -shared -fPIC -g v1.c -o libv1.so
gcc -shared -fPIC -g v2.c -o libv2.so
abicheck compare libv1.so libv2.so --header old=v1.h --header new=v2.h
Expected abicheck finding¶
Verdict: BREAKING (exit 4)
calling_convention_changed vector_dot: (default) -> ms_abi
(no func_return_changed)
Same result with the CastXML and the Clang header backend
(ABICHECK_AST_FRONTEND=castxml|clang).
Minimum evidence¶
L1 (debug info): a Clang-built library carries the convention in DW_AT_calling_convention. GCC emits none, so a GCC build needs the headers (L2), where the macro is read at the declaration.
Why abicheck catches it¶
The CastXML lane reads the declaration's preprocessed line (-E -dD), where
the function-like macro is already expanded. The Clang lane strips the macro
invocation sugar from the function's qualType before reading the return
type, so the return type stays double on both sides.
Runtime failure demonstration¶
gcc app.c -L. -l:libv1.so -Wl,-rpath,. -lm -o app && ./app # 32.0, exit 0
cp libv2.so libv1.so && ./app # wrong result, exit 1
Safe redesign¶
Do not parameterise a public declaration's calling convention per release.
Source files¶
CMakeLists.txtapp.cv1.cv1.hv2.cv2.h
See also: Compatibility Catalog · All BREAKING cases · Category: Breaking · Rule: Calling convention changed via a function-like macro · Subject: Calling convention and integer-model changes.