Add collision-safe status code registry
Replace the consumer-sized status-name array with private sparse storage and accept arbitrary integer status values. Add explicit range reservations with overlap diagnostics, reserve the library's 0-255 compatibility band, and harden pointer and string boundary handling. Update regression coverage and document the required migration for custom status-code consumers.
This commit is contained in:
60
README.md
60
README.md
@@ -4,6 +4,50 @@ This library provides a TRY/CATCH style exception handling mechanism for C.
|
||||
|
||||

|
||||
|
||||
## Upgrade notice: custom status codes
|
||||
|
||||
This version changes how custom status-code names and ownership are managed. Applications and libraries upgrading from an earlier version should review every custom error-code definition and initialization path.
|
||||
|
||||
To comply with the new status-code rules:
|
||||
|
||||
1. Rebuild libakerror and all dependent libraries against the new header.
|
||||
2. Remove `AKERR_MAX_ERR_VALUE` compile definitions and source references. The status-name registry is now sparse and accepts any `int`; consumers no longer configure its size.
|
||||
3. Move custom status codes out of the reserved `0` through `255` range. Use fixed integer constants beginning at `256`, rather than offsets from `AKERR_LAST_ERRNO_VALUE`, so libc changes cannot move your codes.
|
||||
4. Assign a distinct range to every library that may coexist in one process. Coordinate these ranges at the application or dependency-stack level.
|
||||
5. After `akerr_init()` and before raising or naming custom errors, reserve the complete range with `akerr_reserve_status_range()`. Treat every result other than `AKERR_STATUS_RANGE_OK` as an initialization failure.
|
||||
6. Register human-readable names with `akerr_name_for_status()` as before. Every co-resident library must reserve its range for collision detection to be effective.
|
||||
|
||||
For example:
|
||||
|
||||
```c
|
||||
enum {
|
||||
MYLIB_ERR_BASE = 256,
|
||||
MYLIB_ERR_PARSE = MYLIB_ERR_BASE,
|
||||
MYLIB_ERR_STORAGE,
|
||||
MYLIB_ERR_LIMIT
|
||||
};
|
||||
|
||||
int mylib_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
akerr_init();
|
||||
result = akerr_reserve_status_range(
|
||||
MYLIB_ERR_BASE,
|
||||
MYLIB_ERR_LIMIT - MYLIB_ERR_BASE,
|
||||
"mylib");
|
||||
if (result != AKERR_STATUS_RANGE_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
akerr_name_for_status(MYLIB_ERR_PARSE, "Parse Error");
|
||||
akerr_name_for_status(MYLIB_ERR_STORAGE, "Storage Error");
|
||||
return AKERR_STATUS_RANGE_OK;
|
||||
}
|
||||
```
|
||||
|
||||
Repeating the exact same reservation for the same owner is safe. Overlapping ranges, invalid ranges, and exhausted reservation capacity are rejected. Code that directly referenced the former `__AKERR_ERROR_NAMES` data symbol used an undocumented interface and must migrate to `akerr_name_for_status()`.
|
||||
|
||||
# Why?
|
||||
|
||||
There is nothing wrong with C as it is. This library does not claim to fix some problem with C.
|
||||
@@ -64,12 +108,22 @@ Any function which uses the `PREPARE_ERROR` macro should have a return type of `
|
||||
|
||||
The library uses integer values to specify error codes inside of its context. These integer return codes are defined in `akerror.h` in the form of `AKERR_xxxxx` where `xxxxx` is the name of the error code in question. See `akerror.h` for a list of defined errors and their descriptions.
|
||||
|
||||
You can define additional error types by defining additional `AKERR_xxxxx` values. Error values up to 255 are reserved by the library (`AKERR_xxxxx` begins where `errno` stops), so please begin your error values at 256. When you add additional error codes, you need to define `-DAKERR_MAX_ERR_VALUE=n` to the compiler, where `n` is the maximum error code you have defined. If you define custom error codes, `AKERR_MAX_ERR_VALUE` must be >= 256 or the compiler will throw an error.
|
||||
You can define additional error types as integer constants. Values 0 through 255 are reserved by libakerror; consumers should allocate codes starting at 256. Status names are stored sparsely, so there is no maximum status value and no compiler definition is needed.
|
||||
|
||||
Define a human-friendly name for the error with the `akerr_name_for_status` method somewhere in your code's initialization before the error may be used:
|
||||
Libraries that may coexist in one process should reserve their ranges during initialization and treat any nonzero result as a startup error:
|
||||
|
||||
```c
|
||||
akerr_name_for_status(129, "Some Error Code Description")
|
||||
if (akerr_reserve_status_range(256, 16, "my-library") != AKERR_STATUS_RANGE_OK) {
|
||||
/* Refuse to initialize: another component owns part of the range. */
|
||||
}
|
||||
```
|
||||
|
||||
Reservations are process-local, fixed-capacity, and idempotent when the same owner repeats the exact same range. They detect declared range collisions while preserving compile-time integer constants for `HANDLE`. Call `akerr_init()` before reserving ranges. Existing custom codes below 256 should migrate into a declared range at or above 256.
|
||||
|
||||
Define a human-friendly name for the error with `akerr_name_for_status` during initialization before the error may be used:
|
||||
|
||||
```c
|
||||
akerr_name_for_status(256, "Some Error Code Description")
|
||||
```
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user