From: James Jones Date: Thu, 21 Oct 2021 14:07:49 +0000 (-0500) Subject: Add fr_heap_verify() and FR_HEAP_VERIFY() (#4274) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a62820106f8130f82b64344b96cdf619d4b21b3;p=thirdparty%2Ffreeradius-server.git Add fr_heap_verify() and FR_HEAP_VERIFY() (#4274) FR_HEAP_VERIFY() invocations are added to fr_heap_test() to confirm that the verify function works. --- diff --git a/src/lib/util/heap.c b/src/lib/util/heap.c index 2ddc847816a..a780de1ee85 100644 --- a/src/lib/util/heap.c +++ b/src/lib/util/heap.c @@ -58,7 +58,7 @@ typedef struct fr_heap_s heap_t; */ #define HEAP_PARENT(_x) ((_x) >> 1) #define HEAP_LEFT(_x) (2 * (_x)) -/* #define HEAP_RIGHT(_x) (2 * (_x) + 1 ) */ +#define HEAP_RIGHT(_x) (2 * (_x) + 1 ) #define HEAP_SWAP(_a, _b) { void *_tmp = _a; _a = _b; _b = _tmp; } static void fr_heap_bubble(heap_t *h, fr_heap_index_t child); @@ -386,3 +386,46 @@ void *fr_heap_iter_next(fr_heap_t *hp, fr_heap_iter_t *iter) return h->p[*iter]; } + +#ifndef TALLOC_GET_TYPE_ABORT_NOOP +void fr_heap_verify(char const *file, int line, fr_heap_t *hp) +{ + heap_t *h; + + fr_fatal_assert_msg(hp, "CONSISTENCY CHECK FAILED %s[%i]: fr_heap_t pointer was NULL", file, line); + (void) talloc_get_type_abort(hp, fr_heap_t); + + /* + * Allocating the heap structure and the array holding the heap as described in data structure + * texts together is a respectable savings, but it means adding a level of indirection so the + * fr_heap_t * isn't realloc()ed out from under the user, hence the following (and the use of h + * rather than hp to access anything in the heap structure). + */ + h = *hp; + fr_fatal_assert_msg(h, "CONSISTENCY CHECK FAILED %s[%i]: heap_t pointer was NULL", file, line); + (void) talloc_get_type_abort(h, heap_t); + + fr_fatal_assert_msg(h->num_elements <= h->size, + "CONSISTENCY CHECK FAILED %s[%i]: num_elements exceeds size", file, line); + + fr_fatal_assert_msg(h->p[0] == (void *)UINTPTR_MAX, + "CONSISTENCY CHECK FAILED %s[%i]: zeroeth element special value overwritten", file, line); + + for (unsigned int i = 1; i <= h->num_elements; i++) { + void *data = h->p[i]; + + fr_fatal_assert_msg(data, "CONSISTENCY CHECK FAILED %s[%i]: node %u was NULL", file, line, i); + if (h->type) (void)_talloc_get_type_abort(data, h->type, __location__); + fr_fatal_assert_msg(index_get(h, data) == i, + "CONSISTENCY CHECK FAILED %s[%i]: node %u index != %u", file, line, i, i); + } + for (unsigned int i = 1; ; i++) { + if (HEAP_LEFT(i) > h->num_elements) break; + fr_fatal_assert_msg(h->cmp(h->p[i], h->p[HEAP_LEFT(i)]) <= 0, + "CONSISTENCY_CHECK_FAILED %s[%i]: node %u > left child", file, line, i); + if (HEAP_RIGHT(i) > h->num_elements) break; + fr_fatal_assert_msg(h->cmp(h->p[i], h->p[HEAP_RIGHT(i)]) <= 0, + "CONSISTENCY_CHECK_FAILED %s[%i]: node %u > right child", file, line, i); + } +} +#endif diff --git a/src/lib/util/heap.h b/src/lib/util/heap.h index 6ae651ccc7b..ce1256ddea0 100644 --- a/src/lib/util/heap.h +++ b/src/lib/util/heap.h @@ -122,6 +122,14 @@ void *fr_heap_iter_next(fr_heap_t *hp, fr_heap_iter_t *iter) CC_HINT(nonnull); fr_heap_iter_t _iter; \ for (_type *_data = fr_heap_iter_init(_heap, &_iter); _data; _data = fr_heap_iter_next(_heap, &_iter)) +#ifndef TALLOC_GET_TYPE_ABORT_NOOP +void fr_heap_verify(char const *file, int line, fr_heap_t *hp); +# define FR_HEAP_VERIFY(_heap) fr_heap_verify(__FILE__, __LINE__, _heap) +#elif !defined(NDEBUG) +# define FR_HEAP_VERIFY(_heap) fr_assert(_heap) +#else +# define FR_HEAP_VERIFY(_heap) +#endif #ifdef __cplusplus } diff --git a/src/lib/util/heap_tests.c b/src/lib/util/heap_tests.c index 06d6d6db162..c7372e49a53 100644 --- a/src/lib/util/heap_tests.c +++ b/src/lib/util/heap_tests.c @@ -73,6 +73,7 @@ static void heap_test(int skip) TEST_CASE("insertions"); for (i = 0; i < HEAP_TEST_SIZE; i++) { + FR_HEAP_VERIFY(hp); TEST_CHECK((ret = fr_heap_insert(hp, &array[i])) >= 0); TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror()); @@ -87,6 +88,7 @@ static void heap_test(int skip) for (i = 0; i < HEAP_TEST_SIZE / skip; i++) { entry = i * skip; + FR_HEAP_VERIFY(hp); TEST_CHECK(array[entry].heap != 0); TEST_MSG("element %i removed out of order", entry); @@ -105,6 +107,7 @@ static void heap_test(int skip) for (i = 0; i < left; i++) { heap_thing *t; + FR_HEAP_VERIFY(hp); TEST_CHECK((t = fr_heap_peek(hp)) != NULL); TEST_MSG("expected %i elements remaining in the heap", left - i);