Case 42: Type Alignment Changed (standalone alignas)¶
| Field | Value |
|---|---|
| Verdict | ๐ด BREAKING |
| Category | Breaking |
| Platforms | Linux, macOS |
| Flags | ABI break, API break |
Detected ChangeKinds |
โ |
| Source files | examples/case42_type_alignment_changed/ |
Category: Type Layout / DWARF | Verdict: BREAKING
What this case is about¶
v1 defines CacheBlock with aligned(8). v2 increases alignment to
aligned(64) for cache-line optimization. The fields and their types are
identical โ only the alignment attribute changes.
This is a clean, isolated alignment change (unlike case41 which bundles alignment with type removal and enum changes).
What breaks at binary level¶
- sizeof may change: Compilers pad structs to a multiple of their alignment.
aligned(64)makessizeof(CacheBlock)= 64 (padded to alignment boundary). Withaligned(8)it's also 64 here, but the ABI contract about where the struct can live in memory changes. - Stack allocation misaligned: Old binaries allocate
CacheBlockwith 8-byte alignment. The v2 library may use SIMD instructions (e.g.,vmovdqa) that require 64-byte alignment โ SIGBUS / SIGSEGV. - Array stride changes: If sizeof changes,
&blocks[i]computes wrong offsets. - malloc alignment:
malloctypically returns 16-byte aligned memory. 64-byte aligned structs needaligned_alloc(64, sizeof(CacheBlock)).
What abicheck detects¶
TYPE_ALIGNMENT_CHANGED: Detected via DWARFDW_AT_alignmentor inferred fromDW_AT_byte_sizechanges caused by alignment padding.
Overall verdict: BREAKING
How to reproduce¶
gcc -shared -fPIC -g bad.c -include bad.h -o libbad.so
gcc -shared -fPIC -g good.c -include good.h -o libgood.so
python3 -m abicheck.cli dump libbad.so -o /tmp/v1.json
python3 -m abicheck.cli dump libgood.so -o /tmp/v2.json
python3 -m abicheck.cli compare /tmp/v1.json /tmp/v2.json
# โ BREAKING: TYPE_ALIGNMENT_CHANGED
How to fix¶
Use opaque types so callers never allocate or embed the struct directly:
/* header */
typedef struct CacheBlock CacheBlock;
CacheBlock* block_alloc(void); /* library controls alignment */
/* implementation */
struct CacheBlock __attribute__((aligned(64))) { ... };
CacheBlock* block_alloc(void) {
return aligned_alloc(64, sizeof(CacheBlock));
}
Real-world examples¶
- DPDK packet buffers require cache-line alignment (64 bytes).
- Intel TBB / oneTBB uses
alignas(64)for scalable allocator metadata. - Changing alignment in a public struct after release broke ABI in several multimedia libraries (FFmpeg, GStreamer).
References¶
Real Failure Demo¶
Severity: BAD PRACTICE / ABI BREAK
cmake -S examples -B /tmp/abicheck-examples-build -DCMAKE_BUILD_TYPE=Debug
cmake --build /tmp/abicheck-examples-build --target case43_type_alignment_changed_app case43_type_alignment_changed_v2
tmp=$(mktemp -d)
cp /tmp/abicheck-examples-build/case43_type_alignment_changed/app_v1 "$tmp/"
cp /tmp/abicheck-examples-build/case43_type_alignment_changed/libv2.so "$tmp/libv1.so"
(cd "$tmp" && LD_LIBRARY_PATH=. ./app_v1)
# block_process = 0 (expected 4) / WRONG RESULT: alignment change caused array stride/layout mismatch
Source files¶
CMakeLists.txtapp.cbad.cbad.hgood.cgood.h
See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.