Case 31 โ Enum Member Rename¶
| Field | Value |
|---|---|
| Verdict | ๐ API_BREAK |
| Category | API Break |
| Platforms | Linux, macOS, Windows |
| Flags | API break |
Detected ChangeKinds |
enum_member_renamed |
| Source files | browse on GitHub |
Category: Enum API | Verdict: ๐ API_BREAK (binary compatible)
What changes¶
| Member | v1 | v2 | Integer Value |
|---|---|---|---|
| Error level | LOG_ERR |
LOG_ERROR |
1 (unchanged) |
| Warning level | LOG_WARN |
LOG_WARNING |
2 (unchanged) |
| Debug level | LOG_DBG |
LOG_DEBUG |
3 (unchanged) |
LOG_NONE |
present | present | 0 (unchanged) |
LOG_MAX |
present | present | 4 (unchanged) |
Why this IS a break (source-level)¶
Enum constants in C are compiled into immediate integer values in the binary.
Renaming LOG_ERR to LOG_ERROR does not change the compiled output at all โ
the integer 1 is the same regardless of the source name.
Binary compatibility: Fully preserved. Existing binaries call set_log_level(1),
and the v2 library accepts this identically.
Source compatibility: Broken. Any code using LOG_ERR, LOG_WARN, or LOG_DBG
will fail to compile against v2 headers because those identifiers no longer exist.
This forces all downstream consumers to update their source code.
abicheck detects this as ENUM_MEMBER_RENAMED (and ENUM_MEMBER_REMOVED for the
old names).
Code diff¶
typedef enum {
LOG_NONE = 0,
- LOG_ERR = 1,
- LOG_WARN = 2,
- LOG_DBG = 3,
+ LOG_ERROR = 1,
+ LOG_WARNING = 2,
+ LOG_DEBUG = 3,
LOG_MAX = 4
} log_level_t;
Real Failure Demo¶
Severity: MODERATE (source break only)
Scenario: Compile app against v1 headers, swap in v2 .so.
# Build v1 library + app
gcc -shared -fPIC -g v1.c -o libfoo.so
gcc -g app.c -I. -L. -lfoo -Wl,-rpath,. -o app
./app
# โ Enum rename demo (compiled against v1.h):
# โ
# โ Enum values compiled into binary:
# โ LOG_NONE = 0
# โ LOG_ERR = 1
# โ LOG_WARN = 2
# โ LOG_DBG = 3
# โ LOG_MAX = 4
# โ
# โ Calling set_log_level(LOG_ERR) [value=1] ... OK
# โ Calling set_log_level(LOG_WARN) [value=2] ... OK
# โ Calling set_log_level(LOG_DBG) [value=3] ... OK
# Swap in v2 (no recompile)
gcc -shared -fPIC -g v2.c -o libfoo.so
./app
# โ Output is identical โ binary is fully compatible.
# โ The integer values 1, 2, 3 are hardcoded in the binary.
Source break verification:
gcc -g app.c -I. -include v2.h -L. -lfoo -Wl,-rpath,. -o app_v2 2>&1
# โ error: 'LOG_ERR' undeclared
# โ error: 'LOG_WARN' undeclared
# โ error: 'LOG_DBG' undeclared
Reproduce with abicheck¶
gcc -shared -fPIC -g v1.c -o libfoo_v1.so
gcc -shared -fPIC -g v2.c -o libfoo_v2.so
abidw --out-file v1.xml libfoo_v1.so
abidw --out-file v2.xml libfoo_v2.so
abidiff v1.xml v2.xml
echo "exit: $?"
How to fix¶
- Keep the old names as aliases:
#define LOG_ERR LOG_ERROR - Or add both old and new names in the enum with matching values:
LOG_ERR = 1, LOG_ERROR = LOG_ERR - Only remove old names on a major SONAME bump with a deprecation period.
References¶
Source files¶
See also: Examples overview ยท All API_BREAK cases ยท Category: API Break.