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:
113
src/error.c
113
src/error.c
@@ -10,18 +10,48 @@ akerr_ErrorContext *__akerr_last_ignored;
|
||||
akerr_ErrorUnhandledErrorHandler akerr_handler_unhandled_error;
|
||||
akerr_ErrorLogFunction akerr_log_method = NULL;
|
||||
|
||||
char __AKERR_ERROR_NAMES[AKERR_MAX_ERR_VALUE+1][AKERR_MAX_ERROR_NAME_LENGTH];
|
||||
#define AKERR_MAX_REGISTERED_STATUS_NAMES 512
|
||||
#define AKERR_MAX_RESERVED_STATUS_RANGES 64
|
||||
#define AKERR_MAX_STATUS_RANGE_OWNER_LENGTH 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int status;
|
||||
char name[AKERR_MAX_ERROR_NAME_LENGTH];
|
||||
} akerr_StatusName;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int first;
|
||||
int last;
|
||||
char owner[AKERR_MAX_STATUS_RANGE_OWNER_LENGTH];
|
||||
} akerr_StatusRange;
|
||||
|
||||
static akerr_StatusName akerr_status_names[AKERR_MAX_REGISTERED_STATUS_NAMES];
|
||||
static int akerr_status_name_count;
|
||||
static akerr_StatusRange akerr_status_ranges[AKERR_MAX_RESERVED_STATUS_RANGES];
|
||||
static int akerr_status_range_count;
|
||||
|
||||
akerr_ErrorContext AKERR_ARRAY_ERROR[AKERR_MAX_ARRAY_ERROR];
|
||||
|
||||
static void akerr_copy_string(char *destination, int capacity, const char *source)
|
||||
{
|
||||
strncpy(destination, source, (size_t)capacity - 1);
|
||||
destination[capacity - 1] = '\0';
|
||||
}
|
||||
|
||||
int akerr_valid_error_address(akerr_ErrorContext *ptr)
|
||||
{
|
||||
// Is this within the memory region occupied by AKERR_ARRAY_ERROR?
|
||||
if ( ptr == NULL ) {
|
||||
return 1;
|
||||
}
|
||||
return ((ptr >= &AKERR_ARRAY_ERROR[0]) &&
|
||||
(ptr <= &AKERR_ARRAY_ERROR[AKERR_MAX_ARRAY_ERROR-1]));
|
||||
for ( int i = 0; i < AKERR_MAX_ARRAY_ERROR; i++ ) {
|
||||
if ( ptr == &AKERR_ARRAY_ERROR[i] ) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void akerr_default_logger(const char *fmt, ...)
|
||||
@@ -53,7 +83,13 @@ void akerr_init()
|
||||
akerr_log_method = &akerr_default_logger;
|
||||
}
|
||||
akerr_handler_unhandled_error = &akerr_default_handler_unhandled_error;
|
||||
memset((void *)&__AKERR_ERROR_NAMES[0], 0x00, ((AKERR_MAX_ERR_VALUE+1) * AKERR_MAX_ERROR_NAME_LENGTH));
|
||||
memset((void *)&akerr_status_names[0], 0x00, sizeof(akerr_status_names));
|
||||
memset((void *)&akerr_status_ranges[0], 0x00, sizeof(akerr_status_ranges));
|
||||
akerr_status_name_count = 0;
|
||||
akerr_status_range_count = 0;
|
||||
|
||||
/* errno and AKERR_* values are the library-owned compatibility band. */
|
||||
(void)akerr_reserve_status_range(0, 256, "libakerror");
|
||||
|
||||
akerr_name_for_status(AKERR_NULLPOINTER, "Null Pointer Error");
|
||||
akerr_name_for_status(AKERR_OUTOFBOUNDS, "Out Of Bounds Error");
|
||||
@@ -114,15 +150,72 @@ akerr_ErrorContext *akerr_release_error(akerr_ErrorContext *err)
|
||||
}
|
||||
|
||||
|
||||
// returns or sets the name for the given status.
|
||||
// Call with name = NULL to retrieve a status.
|
||||
/* Return or set a name. Status magnitude is unrelated to storage size. */
|
||||
char *akerr_name_for_status(int status, char *name)
|
||||
{
|
||||
if ( status < 0 || status > AKERR_MAX_ERR_VALUE ) {
|
||||
return "Unknown Error";
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < akerr_status_name_count; i++ ) {
|
||||
if ( akerr_status_names[i].status == status ) {
|
||||
if ( name != NULL ) {
|
||||
akerr_copy_string(akerr_status_names[i].name,
|
||||
AKERR_MAX_ERROR_NAME_LENGTH, name);
|
||||
}
|
||||
return akerr_status_names[i].name;
|
||||
}
|
||||
}
|
||||
if ( name != NULL ) {
|
||||
strncpy((char *)&__AKERR_ERROR_NAMES[status], name, AKERR_MAX_ERROR_NAME_LENGTH);
|
||||
if ( akerr_status_name_count == AKERR_MAX_REGISTERED_STATUS_NAMES ) {
|
||||
return "Unknown Error";
|
||||
}
|
||||
i = akerr_status_name_count++;
|
||||
akerr_status_names[i].status = status;
|
||||
akerr_copy_string(akerr_status_names[i].name,
|
||||
AKERR_MAX_ERROR_NAME_LENGTH, name);
|
||||
return akerr_status_names[i].name;
|
||||
}
|
||||
return (char *)&__AKERR_ERROR_NAMES[status];
|
||||
return "Unknown Error";
|
||||
}
|
||||
|
||||
/* Reserve an inclusive status interval and reject collisions. */
|
||||
int akerr_reserve_status_range(int first_status, int count, const char *owner)
|
||||
{
|
||||
int last_status;
|
||||
|
||||
if ( count <= 0 || owner == NULL || owner[0] == '\0' ||
|
||||
strlen(owner) >= AKERR_MAX_STATUS_RANGE_OWNER_LENGTH ||
|
||||
first_status > INT_MAX - (count - 1) ) {
|
||||
return AKERR_STATUS_RANGE_INVALID;
|
||||
}
|
||||
last_status = first_status + count - 1;
|
||||
|
||||
for ( int i = 0; i < akerr_status_range_count; i++ ) {
|
||||
if ( first_status <= akerr_status_ranges[i].last &&
|
||||
last_status >= akerr_status_ranges[i].first ) {
|
||||
if ( first_status == akerr_status_ranges[i].first &&
|
||||
last_status == akerr_status_ranges[i].last &&
|
||||
strcmp(owner, akerr_status_ranges[i].owner) == 0 ) {
|
||||
return AKERR_STATUS_RANGE_OK;
|
||||
}
|
||||
if ( akerr_log_method != NULL ) {
|
||||
akerr_log_method("Status range %d..%d requested by %s overlaps "
|
||||
"%d..%d owned by %s\n",
|
||||
first_status, last_status, owner,
|
||||
akerr_status_ranges[i].first,
|
||||
akerr_status_ranges[i].last,
|
||||
akerr_status_ranges[i].owner);
|
||||
}
|
||||
return AKERR_STATUS_RANGE_OVERLAP;
|
||||
}
|
||||
}
|
||||
if ( akerr_status_range_count == AKERR_MAX_RESERVED_STATUS_RANGES ) {
|
||||
return AKERR_STATUS_RANGE_FULL;
|
||||
}
|
||||
|
||||
akerr_status_ranges[akerr_status_range_count].first = first_status;
|
||||
akerr_status_ranges[akerr_status_range_count].last = last_status;
|
||||
akerr_copy_string(akerr_status_ranges[akerr_status_range_count].owner,
|
||||
AKERR_MAX_STATUS_RANGE_OWNER_LENGTH, owner);
|
||||
akerr_status_range_count++;
|
||||
return AKERR_STATUS_RANGE_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user