From 055ce493c718a0b5675c22a8e75051c82f6c5b48 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 6 Jul 2024 22:05:54 -0500 Subject: [PATCH] Bugfix: The f_memory array append and append all need to allow for sources to be NULL. A valid array that is not allocated will have a size of 0. Passing these to the function should not result in an error. If the size is 0, then there is nothing to copy even though array is NULL This is all fine. Update the documentation comments to be more explicit on NULL in the parameters. --- level_0/f_memory/c/memory/array.c | 6 +- level_0/f_memory/c/memory/array.h | 67 +++++++++++++++++++++- .../tests/unit/c/test-memory-array_append.c | 21 +++++-- .../tests/unit/c/test-memory-array_append_all.c | 25 ++++++++ 4 files changed, 108 insertions(+), 11 deletions(-) diff --git a/level_0/f_memory/c/memory/array.c b/level_0/f_memory/c/memory/array.c index 15530f9..d80db1d 100644 --- a/level_0/f_memory/c/memory/array.c +++ b/level_0/f_memory/c/memory/array.c @@ -23,13 +23,13 @@ extern "C" { #ifndef _di_f_memory_array_append_ f_status_t f_memory_array_append(const void * const source, const size_t width, void ** const array, f_number_unsigned_t * restrict const used, f_number_unsigned_t * restrict const size) { #ifndef _di_level_0_parameter_checking_ - if (!source) return F_status_set_error(F_parameter); if (!width) return F_status_set_error(F_parameter); if (!array) return F_status_set_error(F_parameter); if (!used) return F_status_set_error(F_parameter); if (!size) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ + if (!source) return F_data_not; if (*used >= F_number_t_size_unsigned_d) return F_status_set_error(F_array_too_large); { @@ -55,11 +55,13 @@ extern "C" { #ifndef _di_f_memory_array_append_all_ f_status_t f_memory_array_append_all(const void * const sources, const f_number_unsigned_t amount, const size_t width, void ** const array, f_number_unsigned_t * restrict const used, f_number_unsigned_t * restrict const size) { #ifndef _di_level_0_parameter_checking_ - if (!sources) return F_status_set_error(F_parameter); if (!width) return F_status_set_error(F_parameter); if (!array) return F_status_set_error(F_parameter); if (!used) return F_status_set_error(F_parameter); if (!size) return F_status_set_error(F_parameter); + + // Sources might be un-allocated, so this is not actually an error if amount is 0. + if (!sources && amount) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ if (!amount) return F_data_not; diff --git a/level_0/f_memory/c/memory/array.h b/level_0/f_memory/c/memory/array.h index 86e8482..3e68c3d 100644 --- a/level_0/f_memory/c/memory/array.h +++ b/level_0/f_memory/c/memory/array.h @@ -27,14 +27,21 @@ extern "C" { * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array to resize. + * + * Must not be NULL. * @param used * The structure.used. + * + * Must not be NULL. * @param size * The structure.size. * + * Must not be NULL. + * * @return * F_okay on success. * @@ -53,10 +60,13 @@ extern "C" { * If the simple type that is "array" requires additional memory manipulation on allocation or de-allocation, then do not use this function. * * @param source - * The source structure to copy from. + * A pointer to the source structure to copy from. + * + * May be NULL, which means source is not allocated. * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array destination. @@ -75,13 +85,20 @@ extern "C" { * ... * f_memory_array_append(source, width, (void **) &arr_pounter, used, size); * } + * + * Must not be NULL. * @param used * The structure.used destination. + * + * Must not be NULL. * @param size * The structure.size destination. * + * Must not be NULL. + * * @return * F_okay on success. + * F_data_not on success but source is NULL. * * F_array_too_large (with error bit) if the new array length is too large. * F_memory_not (with error bit) on out of memory. @@ -101,14 +118,18 @@ extern "C" { * Be careful that the resulting multiplication does not overflow f_number_unsigned_t. * * @param sources - * The source structure to copy from. + * A pointer to the source structure to copy from. * This is generally a structure.array value. + * + * May be NULL when amount is 0, which means sources is not allocated. + * May not be NULL when amount is greater than 0. * @param amount * The total length of the sources to copy. * The is generally the structure.used value. * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array destination. @@ -129,9 +150,13 @@ extern "C" { * } * @param used * The structure.used destination. + * + * Must not be NULL. * @param size * The structure.size destination. * + * Must not be NULL. + * * @return * F_okay on success. * F_data_not if amount is 0. @@ -159,14 +184,21 @@ extern "C" { * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array to resize. + * + * Must not be NULL. * @param used * The structure.used. + * + * Must not be NULL. * @param size * The structure.size. * + * Must not be NULL. + * * @return * F_okay on success. * @@ -192,14 +224,21 @@ extern "C" { * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array to resize. + * + * Must not be NULL. * @param used * The structure.used. + * + * Must not be NULL. * @param size * The structure.size. * + * Must not be NULL. + * * @return * F_okay on success. * @@ -218,18 +257,26 @@ extern "C" { * * @param step * The allocation step to use. - * Must be greater than 0. + * + * Must not be 0. * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array to resize. + * + * Must not be NULL. * @param used * The structure.used. + * + * Must not be NULL. * @param size * The structure.size. * + * Must not be NULL. + * * @return * F_okay on success. * F_data_not on success, but there is no reason to increase size (used + 1 <= size). @@ -255,14 +302,21 @@ extern "C" { * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array to resize. + * + * Must not be NULL. * @param used * The structure.used. + * + * Must not be NULL. * @param size * The structure.size. * + * Must not be NULL. + * * @return * F_okay on success. * F_data_not on success, but there is no reason to increase size (used + amount <= size). @@ -286,14 +340,21 @@ extern "C" { * @param width * The size of the structure represented by array. * The word "width" is used due to conflicts of already using "length" and "size". + * * Must not be 0. * @param array * The structure.array to resize. + * + * Must not be NULL. * @param used * The structure.used. + * + * Must not be NULL. * @param size * The structure.size. * + * Must not be NULL. + * * @return * F_okay on success. * diff --git a/level_0/f_memory/tests/unit/c/test-memory-array_append.c b/level_0/f_memory/tests/unit/c/test-memory-array_append.c index 4c8606f..259d030 100644 --- a/level_0/f_memory/tests/unit/c/test-memory-array_append.c +++ b/level_0/f_memory/tests/unit/c/test-memory-array_append.c @@ -10,8 +10,17 @@ void test__f_memory_array_append__parameter_checking(void **state) { const int number = 1; test_memory_array_t data = test_memory_array_t_initialize; + // In this case, the usual parameter checking must not return F_parameter error when source is NULL. { - const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), 0, 0, 0); + const f_status_t status = f_memory_array_append(0, sizeof(int), (void **) &data.array, &data.used, &data.size); + + assert_int_equal(status, F_data_not); + assert_int_equal(data.used, 0); + assert_int_equal(data.size, 0); + } + + { + const f_status_t status = f_memory_array_append(0, sizeof(int), 0, 0, 0); assert_int_equal(status, F_status_set_error(F_parameter)); assert_int_equal(data.used, 0); @@ -19,7 +28,7 @@ void test__f_memory_array_append__parameter_checking(void **state) { } { - const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), 0, &data.used, &data.size); + const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), 0, 0, 0); assert_int_equal(status, F_status_set_error(F_parameter)); assert_int_equal(data.used, 0); @@ -27,7 +36,7 @@ void test__f_memory_array_append__parameter_checking(void **state) { } { - const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), (void **) &data.array, 0, &data.size); + const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), 0, &data.used, &data.size); assert_int_equal(status, F_status_set_error(F_parameter)); assert_int_equal(data.used, 0); @@ -35,7 +44,7 @@ void test__f_memory_array_append__parameter_checking(void **state) { } { - const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), (void **) &data.array, &data.used, 0); + const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), (void **) &data.array, 0, &data.size); assert_int_equal(status, F_status_set_error(F_parameter)); assert_int_equal(data.used, 0); @@ -43,7 +52,7 @@ void test__f_memory_array_append__parameter_checking(void **state) { } { - const f_status_t status = f_memory_array_append((void *) &number, 0, (void **) &data.array, &data.used, &data.size); + const f_status_t status = f_memory_array_append((void *) &number, sizeof(int), (void **) &data.array, &data.used, 0); assert_int_equal(status, F_status_set_error(F_parameter)); assert_int_equal(data.used, 0); @@ -51,7 +60,7 @@ void test__f_memory_array_append__parameter_checking(void **state) { } { - const f_status_t status = f_memory_array_append(0, sizeof(int), (void **) &data.array, &data.used, &data.size); + const f_status_t status = f_memory_array_append((void *) &number, 0, (void **) &data.array, &data.used, &data.size); assert_int_equal(status, F_status_set_error(F_parameter)); assert_int_equal(data.used, 0); diff --git a/level_0/f_memory/tests/unit/c/test-memory-array_append_all.c b/level_0/f_memory/tests/unit/c/test-memory-array_append_all.c index b730e2c..34890ad 100644 --- a/level_0/f_memory/tests/unit/c/test-memory-array_append_all.c +++ b/level_0/f_memory/tests/unit/c/test-memory-array_append_all.c @@ -11,6 +11,31 @@ void test__f_memory_array_append_all__parameter_checking(void **state) { test_memory_array_t sources = { .array = sources_array, .used = 2, .size = 0 }; test_memory_array_t data = test_memory_array_t_initialize; + // In this case, the usual parameter checking must not return F_parameter error when sources is NULL and amount is 0. + { + const f_status_t status = f_memory_array_append_all(0, 0, sizeof(int), (void **) &data.array, &data.used, &data.size); + + assert_int_equal(status, F_data_not); + assert_int_equal(data.used, 0); + assert_int_equal(data.size, 0); + } + + { + const f_status_t status = f_memory_array_append_all(0, sources.used, sizeof(int), (void **) &data.array, &data.used, &data.size); + + assert_int_equal(status, F_status_set_error(F_parameter)); + assert_int_equal(data.used, 0); + assert_int_equal(data.size, 0); + } + + { + const f_status_t status = f_memory_array_append_all(0, 0, sizeof(int), 0, 0, 0); + + assert_int_equal(status, F_status_set_error(F_parameter)); + assert_int_equal(data.used, 0); + assert_int_equal(data.size, 0); + } + { const f_status_t status = f_memory_array_append_all((void *) sources.array, sources.used, sizeof(int), 0, 0, 0); -- 1.8.3.1