Skip to content

Case 210: Calling Convention Respelled via a Macro

Field Value
Verdict ✅ NO_CHANGE
Category No Change
Classification Rule
Platforms Linux
Flags —
Detected ChangeKinds —
Source files catalog/cases/case210_calling_convention_respelled_via_macro/
Rule family calling-convention-respelled-via-macro
Subject Safe changes correctly not flagged

Category: No change | Verdict: ✅ NO_CHANGE

Verdict and consumer impact

The negative control for case209_calling_convention_changed_via_macro. v1 declares vector_dot/vector_scale with a literal __attribute__((ms_abi)); v2 introduces #define MATHLIB_CALL __attribute__((ms_abi)) and declares MATHLIB_CALL double vector_dot(...). The declaration text changes, but the convention it expands to does not. Both libraries are built ms_abi, so the binary interface is identical and an unchanged old consumer works against either — nothing for abicheck to report.

Old/new diff

v1.h v2.h
__attribute__((ms_abi)) double vector_dot(...); #define MATHLIB_CALL __attribute__((ms_abi))
MATHLIB_CALL double 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: NO_CHANGE (exit 0)

calling_convention_changed and func_return_changed must both stay absent. Verified identically with ABICHECK_AST_FRONTEND=castxml and ABICHECK_AST_FRONTEND=clang.

Minimum evidence

min_evidence: L2 — the only difference between the two versions is in the public header text; the binaries (and their DWARF) are the same. Below the header AST the two sides are trivially identical and the case proves nothing.

Why abicheck catches it

abicheck compares the effective convention per function after macro expansion, not the declaration's spelling. A text-level recovery that read only the literal tokens would see ms_abi on the v1 side and an opaque MATHLIB_CALL on the v2 side and manufacture a convention (or return-type) change; this case pins that it does not.

Runtime failure demonstration

There is none — that is the point of the control.

gcc -shared -fPIC -g v1.c -o libv1.so
gcc -g app.c -L. -lv1 -Wl,-rpath,'$ORIGIN' -o app -lm
./app                                    # dot product = 32.0, scaled = {2.0, 4.0, 6.0}   exit 0
gcc -shared -fPIC -g v2.c -o libv1.so    # swap in v2, no recompile
./app                                    # dot product = 32.0, scaled = {2.0, 4.0, 6.0}   exit 0

Safe redesign

Nothing to redesign: routing an existing convention through a macro is a safe refactoring as long as the macro's expansion matches the shipped convention on every platform.

Cross-tool comparison

abidw --out-file v1.xml libv1.so
abidw --out-file v2.xml libv2.so
abidiff v1.xml v2.xml    # no changes: the binaries are identical

Source files

  • CMakeLists.txt
  • app.c
  • v1.c
  • v1.h
  • v2.c
  • v2.h

See also: Compatibility Catalog · All NO_CHANGE cases · Category: No Change · Rule: Calling convention respelled via a macro · Subject: Safe changes correctly not flagged.