Skip to content

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.txt
  • app.c
  • v1.c
  • v1.h
  • v2.c
  • v2.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.