From 8485ad25e42c922cbbe52f12d6084d5767be1f83 Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Sat, 13 Dec 2025 16:47:40 +0100 Subject: [PATCH] bounds checked arrays --- cig.h | 8 ++++++ dyn_array.c | 15 ++++++++++ test_dynamic_array.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/cig.h b/cig.h index cd68e38..4cf96a3 100644 --- a/cig.h +++ b/cig.h @@ -180,6 +180,14 @@ size_t arr_cap(void *this); #define arr_pop(THIS) (arr_shrink(THIS, 1), THIS[arr_len(THIS)]) +void dyn_array_bounds_check_func(void *this, size_t index, const char *file, int line); + +#define arr_get(THIS, INDEX) \ + (dyn_array_bounds_check_func(THIS, INDEX, __FILE__, __LINE__), (THIS)[INDEX]) + +#define arr_set(THIS, INDEX, VALUE) \ + (dyn_array_bounds_check_func(THIS, INDEX, __FILE__, __LINE__), (THIS)[INDEX] = (VALUE)) + #define STATIC_ASSERT(expr) ((void)sizeof(char[(expr) ? 1 : -1])) bool dyn_array_contains_func(void *this, uint8_t *value); diff --git a/dyn_array.c b/dyn_array.c index 32ecd28..c5ece80 100644 --- a/dyn_array.c +++ b/dyn_array.c @@ -96,6 +96,21 @@ bool dyn_array_contains_cmp_func(void *this, uint8_t *value, dyn_array_eq_fn eq) return false; } +void dyn_array_bounds_check_func(void *this, size_t index, const char *file, int line) { + size_t len = arr_len(this); + if (index >= len) { + fprintf( + stderr, + "%s:%d: array index %zu out of bounds (length is %zu)\n", + file, + line, + index, + len + ); + exit(1); + } +} + void dyn_array_insert_sorted_func(void **this_ptr, const void *value, dyn_array_cmp_fn cmp, const char *file, int line) { void *this = *this_ptr; dyn_array_header_t *header = PTR_FROM_FIELD_PTR(dyn_array_header_t, bytes, this); diff --git a/test_dynamic_array.c b/test_dynamic_array.c index e55da38..08a591b 100644 --- a/test_dynamic_array.c +++ b/test_dynamic_array.c @@ -293,3 +293,70 @@ Test(dynamic_arrays, contains_cmp_key_value_map) { } } +Test(dynamic_arrays, get_valid_indices) { + with_borrow(alloc) { + int *arr = make_arr(alloc, int); + arr_append(arr, 10); + arr_append(arr, 20); + arr_append(arr, 30); + arr_append(arr, 40); + + cr_assert_eq(arr_get(arr, 0), 10); + cr_assert_eq(arr_get(arr, 1), 20); + cr_assert_eq(arr_get(arr, 2), 30); + cr_assert_eq(arr_get(arr, 3), 40); + } +} + +Test(dynamic_arrays, set_valid_indices) { + with_borrow(alloc) { + int *arr = make_arr(alloc, int); + arr_append(arr, 10); + arr_append(arr, 20); + arr_append(arr, 30); + + arr_set(arr, 0, 100); + arr_set(arr, 1, 200); + arr_set(arr, 2, 300); + + cr_assert_eq(arr_get(arr, 0), 100); + cr_assert_eq(arr_get(arr, 1), 200); + cr_assert_eq(arr_get(arr, 2), 300); + } +} + +Test(dynamic_arrays, get_out_of_bounds, .exit_code = 1) { + with_borrow(alloc) { + int *arr = make_arr(alloc, int); + arr_append(arr, 10); + arr_append(arr, 20); + + (void)arr_get(arr, 2); + } +} + +Test(dynamic_arrays, set_out_of_bounds, .exit_code = 1) { + with_borrow(alloc) { + int *arr = make_arr(alloc, int); + arr_append(arr, 10); + arr_append(arr, 20); + + arr_set(arr, 2, 999); + } +} + +Test(dynamic_arrays, get_empty_array, .exit_code = 1) { + with_borrow(alloc) { + int *arr = make_arr(alloc, int); + (void)arr_get(arr, 0); + } +} + +Test(dynamic_arrays, set_empty_array, .exit_code = 1) { + with_borrow(alloc) { + int *arr = make_arr(alloc, int); + arr_set(arr, 0, 42); + } +} + +