integrity p4

This commit is contained in:
Gregory Burd 2024-03-22 16:08:43 -04:00
parent 11a96bdb6e
commit 031c9e2a6b

View file

@ -227,8 +227,8 @@
* return cmp(list, a, b, aux); * return cmp(list, a, b, aux);
* } * }
*/ */
#define SKIP_COMPARATOR(list, type, fn_blk) \ #define SKIP_COMPARATOR(list, decl, fn_blk) \
int __skip_cmp_##type(struct list *head, struct type *a, struct type *b, void *aux) \ int __skip_cmp_##decl(struct list *head, struct decl *a, struct decl *b, void *aux) \
{ \ { \
if (a == b) \ if (a == b) \
return 0; \ return 0; \
@ -985,146 +985,175 @@
return NULL; \ return NULL; \
} }
#define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \ #define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \
/* -- __skip_integrity_failure_ */ \ /* -- __skip_integrity_failure_ */ \
static void __attribute__((format(printf, 1, 2))) __skip_integrity_failure_##decl(const char *fmt, ...) \ static void __attribute__((format(printf, 1, 2))) __skip_integrity_failure_##decl(const char *fmt, ...) \
{ \ { \
va_list args; \ va_list args; \
__skip_debugf(fmt, args); \ __skip_debugf(fmt, args); \
} \ } \
\ \
/* -- __skip_integrity_check_ */ \ /* -- __skip_integrity_check_ */ \
static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \ static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \
{ \ { \
size_t size; \ unsigned nth, n_err = 0; \
unsigned nth, n_err = 0; \ decl##_node_t *node, *prev, *next; \
decl##_node_t *node; \ struct __skiplist_##decl_idx *this; \
struct __skiplist_##decl_idx *this, *that, *prev, *next; \ \
\ if (slist == NULL) { \
if (slist == NULL) { \ __skip_integrity_failure_##decl("slist was NULL, nothing to check"); \
__skip_integrity_failure_##decl("slist was NULL, nothing to check"); \ n_err++; \
n_err++; \ return n_err; \
return n_err; \ } \
} \ \
\ /* Check the Skiplist header (slh) */ \
/* Check the Skiplist header (slh) */ \ \
\ if (slist->slh_head == NULL) { \
if (slist->slh_head == NULL) { \ __skip_integrity_failure_##decl("skiplist slh_head is NULL"); \
__skip_integrity_failure_##decl("skiplist slh_head is NULL"); \ n_err++; \
n_err++; \ return n_err; \
return n_err; \ } \
} \ \
\ if (slist->slh_tail == NULL) { \
if (slist->slh_tail == NULL) { \ __skip_integrity_failure_##decl("skiplist slh_tail is NULL"); \
__skip_integrity_failure_##decl("skiplist slh_tail is NULL"); \ n_err++; \
n_err++; \ return n_err; \
return n_err; \ } \
} \ \
\ if (slist->cmp == NULL) { \
if (slist->cmp == NULL) { \ __skip_integrity_failure_##decl("skiplist comparison function (cmp) is NULL"); \
__skip_integrity_failure_##decl("skiplist comparison function (cmp) is NULL"); \ n_err++; \
n_err++; \ return n_err; \
return n_err; \ } \
} \ \
\ if (slist->max < 2) { \
if (slist->max < 2) { \ __skip_integrity_failure_##decl("skiplist max level must be 1 at minimum"); \
__skip_integrity_failure_##decl("skiplist max level must be 1 at minimum"); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ \
\ if (slist->level >= slist->max) { \
if (slist->level >= slist->max) { \ /* level is 0-based, max of 12 means level cannot be > 11 */ \
/* level is 0-based, max of 12 means level cannot be > 11 */ \ __skip_integrity_failure_##decl("skiplist level in header was >= max"); \
__skip_integrity_failure_##decl("skiplist level in header was >= max"); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ \
\ if (SKIPLIST_MAX_HEIGHT < 1) { \
if (SKIPLIST_MAX_HEIGHT < 1) { \ __skip_integrity_failure_##decl("SKIPLIST_MAX_HEIGHT cannot be less than 1"); \
__skip_integrity_failure_##decl("SKIPLIST_MAX_HEIGHT cannot be less than 1"); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ \
\ if (SKIPLIST_MAX_HEIGHT > 0 && slist->max > SKIPLIST_MAX_HEIGHT) { \
if (SKIPLIST_MAX_HEIGHT > 0 && slist->max > SKIPLIST_MAX_HEIGHT) { \ __skip_integrity_failure_##decl("slist->max cannot be greater than SKIPLIST_MAX_HEIGHT"); \
__skip_integrity_failure_##decl("slist->max cannot be greater than SKIPLIST_MAX_HEIGHT"); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ \
\ node = slist->slh_head; \
node = slist->slh_head; \ for (nth = 0; nth < node->field.sle.height; nth++) { \
for (nth = 0; nth < node->field.sle.height; nth++) { \ if (node->field.sle.next[nth] == NULL) { \
if (node->field.sle.next[nth] == NULL) { \ __skip_integrity_failure_##decl("the head's %u next node should not be NULL", nth); \
__skip_integrity_failure_##decl("the head's %u next node should not be NULL", nth); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ if (node->field.sle.next[nth] == slist->slh_tail) \
if (node->field.sle.next[nth] == slist->slh_tail) \ break; \
break; \ } \
} \ for (; nth < node->field.sle.height; nth++) { \
for (; nth < node->field.sle.height; nth++) { \ if (node->field.sle.next[nth] == NULL) { \
if (node->field.sle.next[nth] == NULL) { \ __skip_integrity_failure_##decl("the head's %u next node should not be NULL", nth); \
__skip_integrity_failure_##decl("the head's %u next node should not be NULL", nth); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ if (node->field.sle.next[nth] != slist->slh_tail) { \
if (node->field.sle.next[nth] != slist->slh_tail) { \ __skip_integrity_failure_##decl("after internal nodes, the head's %u next node should always be the tail", nth); \
__skip_integrity_failure_##decl("after internal nodes, the head's %u next node should always be the tail", nth); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ } \
} \ \
\ if (slist->length > 0 && slist->slh_tail->field.sle.prev == slist->slh_head) { \
if (slist->length > 0 && slist->slh_tail->field.sle.prev == slist->slh_head) { \ __skip_integrity_failure_##decl("slist->length is 0, but tail->prev == head, not an internal node"); \
__skip_integrity_failure_##decl("slist->length is 0, but tail->prev == head, not an internal node"); \ n_err++; \
n_err++; \ if (flags) \
if (flags) \ return n_err; \
return n_err; \ } \
} \ \
\ /* Validate the head node */ \
/* Validate the head node */ \ \
\ /* Validate the tail node */ \
/* Validate the tail node */ \ \
\ /* Validate each node */ \
/* Validate each node */ \ nth = 0; \
nth = 0; \ node = prefix##skip_head_##decl(slist); \
size = prefix##skip_size_##decl(slist); \ while (node) { \
node = prefix##skip_head_##decl(slist); \ this = &node->field.sle; \
while (node) { \ if (this->next == NULL) { \
this = &node->field.sle; \ __skip_integrity_failure_##decl("the %uth node's [%p] next field should never NULL", nth, (void *)node); \
if (this->next == NULL) { \ n_err++; \
__skip_integrity_failure_##decl("the %u node's [%p] next field should never NULL", nth, (void *)node); \ if (flags) \
n_err++; \ return n_err; \
if (flags) \ } \
return n_err; \ if (this->prev == NULL) { \
} \ __skip_integrity_failure_##decl("the %u node [%p] prev field should never NULL", nth, (void *)node); \
if (this->prev == NULL) { \ n_err++; \
__skip_integrity_failure_##decl("the %u node [%p] prev field should never NULL", nth, (void *)node); \ if (flags) \
n_err++; \ return n_err; \
if (flags) \ } \
return n_err; \ uintptr_t a = (uintptr_t)this->next; \
} \ uintptr_t b = (intptr_t)((uintptr_t)node + sizeof(decl##_node_t)); \
uintptr_t a = (uintptr_t)this->next; \ if (a != b) { \
uintptr_t b = (intptr_t)((uintptr_t)node + sizeof(decl##_node_t)); \ __skip_integrity_failure_##decl("the %uth node's [%p] next field isn't at the proper offset relative to the node", nth, (void *)node); \
if (a != b) { \ n_err++; \
__skip_integrity_failure_##decl("the %u node's [%p] next field isn't at the proper offset relative to the node", nth, (void *)node); \ if (flags) \
n_err++; \ return n_err; \
if (flags) \ } \
return n_err; \ next = this->next[0]; \
} \ prev = this->prev; \
\ if (__skip_key_compare_##decl(slist, node, node, slist->aux) != 0) { \
node = prefix##skip_next_node_##decl(slist, node); \ __skip_integrity_failure_##decl("the %uth node [%p] is not equal to itself", nth, (void *)node); \
nth++; \ n_err++; \
} \ if (flags) \
\ return n_err; \
return 0; \ } \
if (__skip_key_compare_##decl(slist, node, prev, slist->aux) < 0) { \
__skip_integrity_failure_##decl("the %uth node [%p] is not greater than the prev node [%p]", nth, (void *)node, (void *)prev); \
n_err++; \
if (flags) \
return n_err; \
} \
if (__skip_key_compare_##decl(slist, node, next, slist->aux) > 0) { \
__skip_integrity_failure_##decl("the %uth node [%p] is not less than the next node [%p]", nth, (void *)node, (void *)next); \
n_err++; \
if (flags) \
return n_err; \
} \
if (__skip_key_compare_##decl(slist, prev, node, slist->aux) > 0) { \
__skip_integrity_failure_##decl("the prev node [%p] is not less than the %uth node [%p]", (void *)prev, nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
if (__skip_key_compare_##decl(slist, next, node, slist->aux) < 0) { \
__skip_integrity_failure_##decl("the next node [%p] is not greater than the %uth node [%p]", (void *)next, nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
node = prefix##skip_next_node_##decl(slist, node); \
nth++; \
} \
\
return 0; \
} }
#define SKIPLIST_KV_ACCESS(decl, prefix, ktype, vtype, qblk, rblk) \ #define SKIPLIST_KV_ACCESS(decl, prefix, ktype, vtype, qblk, rblk) \