Case 26 โ Union Field Added¶
| Field | Value |
|---|---|
| Verdict | ๐ด BREAKING |
| Category | Breaking |
| Platforms | Linux, macOS, Windows |
| Flags | ABI break |
Detected ChangeKinds |
โ |
| Source files | browse on GitHub |
Verdict: ๐ด BREAKING abicheck verdict: BREAKING (TYPE_SIZE_CHANGED: union grows 4โ8 bytes)
What changes¶
| Version | Definition |
|---|---|
| v1 | union Value { int i; float f; }; |
| v2 | union Value { int i; float f; double d; }; |
Why this IS a binary ABI break¶
Adding double d makes double the largest member, so sizeof(union Value) grows
from 4 bytes (max of int=4, float=4) to 8 bytes (double=8).
This is a TYPE_SIZE_CHANGED break because:
- Old callers allocate 4 bytes for union Value on the stack or in a struct.
- The v2 library's fill() may write 8 bytes, overwriting adjacent memory.
- Array indexing breaks: Value arr[10] โ old caller: 40 bytes, library expects 80 bytes.
All union fields still share offset 0, so the field layout is unchanged โ but the size change makes this BREAKING, not just informational.
What it does affect¶
- Union size:
sizeof(union Value)grows 4โ8 bytes โ TYPE_SIZE_CHANGED โ BREAKING. - Struct embedding: any struct containing
union Valuealso grows, shifting later fields. - Array indexing:
Value arr[N]stride changes from 4 to 8 bytes.
Contrast with other union changes¶
| Change | Verdict | Why |
|---|---|---|
| Field added (no size change) | COMPATIBLE | Existing fields at offset 0 unchanged, sizeof same |
| Field added (size grows) | BREAKING | TYPE_SIZE_CHANGED โ callers under-allocate |
| Field removed | BREAKING | Removes a valid representation |
| Field type changed | BREAKING | Reinterpretation of shared storage |
Code diff¶
Real Failure Demo¶
Severity: BREAKING (TYPE_SIZE_CHANGED)
Scenario: app reads v.i after fill(). Adding a double d field doesn't affect int i
access โ but the union is now 8 bytes. Any caller that stack-allocated 4 bytes and passes
&v to a v2 function that writes 8 bytes has a stack overflow.
# Build old lib + app
gcc -shared -fPIC -g old/lib.c -Iold -o libval.so
gcc -g app.c -Iold -L. -lval -Wl,-rpath,. -o app
./app
# โ v.i = 42 (expected 42)
# Swap in new lib (double field added โ sizeof grows 4โ8 bytes)
gcc -shared -fPIC -g new/lib.c -Inew -o libval.so
./app
# โ v.i = 42 (expected 42) โ may still appear correct for int-only access
# But: abicheck reports TYPE_SIZE_CHANGED (4โ8) โ BREAKING
Why BREAKING: sizeof(union Value) grows from 4 to 8 bytes due to double d.
Old callers that allocate union Value on the stack or embed it in a struct
under-allocate memory when running against the v2 library. abicheck correctly
reports TYPE_SIZE_CHANGED โ BREAKING verdict.
Why runtime result may differ from verdict¶
Union field added (double): sizeof(Value) grows 4โ8 bytes, layout broken
Runtime note¶
v2 now writes the newly added double field so old-layout callers observe incompatible behavior.
References¶
Source files¶
See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.