Case 19 โ Enum Member Removed¶
| Field | Value |
|---|---|
| Verdict | ๐ด BREAKING |
| Category | Breaking |
| Platforms | Linux, macOS, Windows |
| Flags | ABI break, API break |
Detected ChangeKinds |
enum_member_removed |
| Source files | browse on GitHub |
Verdict: ๐ด BREAKING Verdict detail: ABI break (symbol removed) + API break (enum value missing from header) abicheck verdict: BREAKING
What changes¶
| Version | Definition |
|---|---|
| v1 | enum Status { OK = 0, ERROR = 1, FOO = 2 }; |
| v2 | enum Status { OK = 0, ERROR = 1 }; |
What breaks at binary level¶
Removing an enum member invalidates any code that uses that member's numeric value.
Existing binaries that were compiled with FOO = 2 may store, transmit, or switch on
that value. The new library no longer defines that value as a valid member of the enum.
This is a semantic ABI break: while the remaining values (OK, ERROR) are still
at the same numeric positions, the removed value FOO = 2 becomes undefined in the
new version. Persisted data, protocol messages, or configuration files that contain
the removed value will be misinterpreted.
Consumer impact¶
/* consumer compiled against v1 */
enum Status s = FOO; /* s = 2 */
write_to_file(s);
/* later, same consumer reads back value 2 with v2 library */
/* library has no FOO โ value 2 is undefined behavior */
Mitigation¶
- Never remove released enum members; mark them as deprecated instead.
- Map legacy values deliberately in deserialization/protocol handling.
- Use explicit sentinel values (e.g.,
STATUS_MAX) to define valid ranges.
Code diff¶
Real Failure Demo¶
Severity: CRITICAL
Scenario: app compiled with old header (has FOO=2) calls library that returns value 2. With v2, FOO is removed โ the value 2 is undefined.
# Build old lib + app
gcc -shared -fPIC -g old/lib.c -Iold -o libstatus.so
gcc -g app.c -Iold -L. -lstatus -Wl,-rpath,. -o app
./app
# โ FOO
# Swap in new lib (FOO removed, but still returns integer 2)
gcc -shared -fPIC -g new/lib.c -Inew -o libstatus.so
./app
# โ FOO โ prints "FOO" because value 2 still matches the compiled switch case
# but in new headers this value is UNDEFINED โ semantic break
# Any consumer recompiled against new headers would get no FOO case โ "UNKNOWN: 2"
Why CRITICAL: Old binaries still "work" but carry a time bomb โ any serialized,
stored, or transmitted value of FOO (integer 2) is now undefined in the new API.
Recompiled consumers get no FOO case and fall through to default, silently
mishandling the value.
Why runtime result may differ from verdict¶
Enum value removal: binary compat (integers same), semantic/protocol break
References¶
Source files¶
See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.