From 7662af09f880802e19d58c043b9838f85375cd02 Mon Sep 17 00:00:00 2001 From: laentropia Date: Wed, 15 Apr 2026 17:17:54 -0600 Subject: [PATCH] test: Added test for init and destroy Also changed a few things like destroy tanking a double pointer so that is more secure and making sure before hand that capacity is not that ridiculous of a size, still, shit can get pass but generally is fine --- include/arraylist.h | 3 +- src/arraylist.c | 83 +++++++++++++++++++++++------------- test/test_arraylist.c | 98 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 32 deletions(-) diff --git a/include/arraylist.h b/include/arraylist.h index 273c972..353d286 100644 --- a/include/arraylist.h +++ b/include/arraylist.h @@ -16,6 +16,7 @@ typedef enum { ARRLIST_OK = 0, ARRLIST_OUT_OF_BOUNDS, ARRLIST_BAD_ALLOC, + ARRLIST_ALLOC_OVERFLOW, ARRLIST_EMPTY, ARRLIST_NULL_ARG, ARRLIST_INVALID_ELEM_SIZE, @@ -23,7 +24,7 @@ typedef enum { } ArrayListErr; ArrayList *arraylist_init(size_t capacity, size_t elem_size); -ArrayListErr arraylist_destroy(ArrayList *arr); +ArrayListErr arraylist_destroy(ArrayList **arr); ArrayListErr arraylist_clear(ArrayList *arr); size_t arraylist_size(const ArrayList *arr); diff --git a/src/arraylist.c b/src/arraylist.c index a662f50..494467d 100644 --- a/src/arraylist.c +++ b/src/arraylist.c @@ -26,6 +26,10 @@ ArrayList *arraylist_init(size_t capacity, size_t elem_size) { return NULL; } + if (capacity > SIZE_MAX / elem_size) { + return NULL; + } + ArrayList *arr = malloc(sizeof(ArrayList)); if (arr == NULL) { return NULL; @@ -42,17 +46,16 @@ ArrayList *arraylist_init(size_t capacity, size_t elem_size) { return arr; } -ArrayListErr arraylist_destroy(ArrayList *arr) { - if (arr == NULL) { +ArrayListErr arraylist_destroy(ArrayList **arr) { + if (arr == NULL || *arr == NULL) { return ARRLIST_NULL_ARG; } - arr->capacity = 0; - arr->elem_size = 0; - arr->len = 0; - free(arr->buffer); - arr->buffer = NULL; - free(arr); + // No problem on using free on NULL :) + free((*arr)->buffer); + free(*arr); + *arr = NULL; + return ARRLIST_OK; } @@ -94,10 +97,16 @@ static ArrayListErr arraylist_grow(ArrayList *arr) { // and only used by funtions that already verified // arr is not null, same with shrink. size_t new_capacity = arr->capacity * 2; + + if (new_capacity > SIZE_MAX / arr->elem_size) { + return ARRLIST_ALLOC_OVERFLOW; + } + void *tmp = realloc(arr->buffer, new_capacity * arr->elem_size); if (tmp == NULL) { return ARRLIST_BAD_ALLOC; } + arr->capacity = new_capacity; arr->buffer = tmp; return ARRLIST_OK; @@ -105,10 +114,16 @@ static ArrayListErr arraylist_grow(ArrayList *arr) { static ArrayListErr arraylist_shrink(ArrayList *arr) { size_t new_capacity = arr->capacity / 2; + + if (new_capacity > SIZE_MAX / arr->elem_size) { + return ARRLIST_ALLOC_OVERFLOW; + } + void *tmp = realloc(arr->buffer, new_capacity *arr->elem_size); if (tmp == NULL) { return ARRLIST_BAD_ALLOC; } + arr->capacity = new_capacity; arr->buffer = tmp; return ARRLIST_OK; @@ -146,14 +161,17 @@ ArrayListErr arraylist_push_front(ArrayList *arr, void *data) { } // No problem if array is full because it grows if it's full - for (size_t i = arr->len - 1; i >= 0; i--) { - memcpy( - arr->buffer + ((i + 1) * arr->elem_size), - arr->buffer + (i * arr->elem_size), - arr->elem_size); - } + memmove( + arr->buffer, + arr->buffer + arr->elem_size, + (arr->len - 1) * arr->elem_size + ); + + memcpy( + arr->buffer, + data, + arr->elem_size); - memcpy(arr->buffer, data, arr->elem_size); arr->len++; return ARRLIST_OK; @@ -164,7 +182,7 @@ ArrayListErr arraylist_insert(ArrayList *arr, size_t index, void *data) { return ARRLIST_NULL_ARG; } - if (index >= arr->len) { + if (index > arr->len) { return ARRLIST_OUT_OF_BOUNDS; } @@ -175,14 +193,15 @@ ArrayListErr arraylist_insert(ArrayList *arr, size_t index, void *data) { } } - for (size_t i = arr->len - 1; i >= index; i--) { - memcpy( - arr->buffer + ((i + 1) * arr->elem_size), - arr->buffer + (i * arr->elem_size), - arr->elem_size); - } + memmove( + arr->buffer + ((index + 1) * arr->elem_size), + arr->buffer + (index * arr->elem_size), + (arr->len - index) * arr->elem_size); + + memcpy(arr->buffer + (index * arr->elem_size), + data, + arr->elem_size); - memcpy(arr->buffer + (index * arr->elem_size), data, arr->elem_size); arr->len++; return ARRLIST_OK; @@ -240,12 +259,10 @@ ArrayListErr arraylist_pop_front(ArrayList *arr, void *out) { ); } - for (size_t i = 0; i < arr->len; i++) { - memcpy( - arr->buffer + (i * arr->elem_size), - arr->buffer + ((i + 1) * arr->elem_size), - arr->elem_size); - } + memmove( + arr->buffer + arr->elem_size, + arr->buffer, + (arr->len - 1) * arr->elem_size); arr->len--; @@ -329,6 +346,10 @@ ArrayListErr arraylist_resize(ArrayList *arr, size_t new_capacity) { return ARRLIST_INVALID_CAPACITY; } + if (new_capacity > SIZE_MAX / arr->elem_size) { + return ARRLIST_ALLOC_OVERFLOW; + } + uint8_t *tmp = realloc(arr->buffer, new_capacity * arr->elem_size); if (tmp == NULL) { return ARRLIST_BAD_ALLOC; @@ -348,6 +369,10 @@ ArrayListErr arraylist_reserve(ArrayList *arr, size_t size_to_reserve) { return ARRLIST_INVALID_CAPACITY; } + if (arr->capacity + size_to_reserve > SIZE_MAX / arr->elem_size) { + return ARRLIST_ALLOC_OVERFLOW; + } + uint8_t *tmp = realloc( arr->buffer, (arr->capacity + size_to_reserve) * arr->elem_size); diff --git a/test/test_arraylist.c b/test/test_arraylist.c index 24acc10..a136489 100644 --- a/test/test_arraylist.c +++ b/test/test_arraylist.c @@ -1,5 +1,99 @@ -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arraylist.h" + +static void test_init_valid_parameters(void **state) { + (void) state; + + ArrayList *arr = arraylist_init(64, sizeof(int)); + assert_ptr_not_equal(arr, NULL); + arraylist_destroy(&arr); +} + +static void test_init_zero_capacity(void **state) { + (void) state; + + ArrayList *arr = arraylist_init(0, sizeof(int)); + assert_ptr_equal(arr, NULL); + arraylist_destroy(&arr); +} + +static void test_init_zero_elem_size(void **state) { + (void) state; + + ArrayList *arr = arraylist_init(64, 0); + assert_ptr_equal(arr, NULL); + arraylist_destroy(&arr); +} + +static void test_init_large_capacity(void **state) { + (void) state; + + ArrayList *arr = arraylist_init(SIZE_MAX, sizeof(int)); + assert_ptr_equal(arr, NULL); + arraylist_destroy(&arr); +} + +static void test_destroy_valid_array(void **state) { + (void) state; + + ArrayList *arr = arraylist_init(64, sizeof(int)); + assert_ptr_not_equal(arr, NULL); + + arraylist_destroy(&arr); + assert_ptr_equal(arr, NULL); +} + +static void test_destroy_null_array(void **state) { + (void) state; + + ArrayList *arr = NULL; + ArrayListErr err = arraylist_destroy(&arr); + + assert_ptr_equal(arr, NULL); + assert_int_equal(err, ARRLIST_NULL_ARG); +} + +static void test_destroy_double(void **state) { + (void) state; + + ArrayList *arr = arraylist_init(64, sizeof(int)); + assert_ptr_not_equal(arr, NULL); + + ArrayListErr err = arraylist_destroy(&arr); + assert_int_equal(err, ARRLIST_OK); + assert_ptr_equal(arr, NULL); + + err = arraylist_destroy(&arr); + assert_int_equal(err, ARRLIST_NULL_ARG); + assert_ptr_equal(arr, NULL); +} int main(void) { - return EXIT_SUCCESS; + const struct CMUnitTest init[] = { + cmocka_unit_test(test_init_valid_parameters), + cmocka_unit_test(test_init_zero_capacity), + cmocka_unit_test(test_init_zero_elem_size), + cmocka_unit_test(test_init_large_capacity), + }; + + const struct CMUnitTest destroy[] = { + cmocka_unit_test(test_destroy_valid_array), + cmocka_unit_test(test_destroy_null_array), + cmocka_unit_test(test_destroy_double), + }; + + int rc = 0; + + rc += cmocka_run_group_tests(init, NULL, NULL); + rc += cmocka_run_group_tests(destroy, NULL, NULL); + + return rc; }