From f11798ae8af2732bd69333c2aea91e7d08cf0e8a Mon Sep 17 00:00:00 2001 From: Aysha Arah Date: Wed, 24 Jun 2026 19:05:48 +0530 Subject: [PATCH] Add cupsArrayDup test and overflow protection in array allocation --- cups/array.c | 49 +++++++++++++++++--- tests/README.md | 19 ++++++++ tests/test_array_dup.c | 100 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 tests/README.md create mode 100644 tests/test_array_dup.c diff --git a/cups/array.c b/cups/array.c index ab627d66c..28f0b994a 100644 --- a/cups/array.c +++ b/cups/array.c @@ -58,6 +58,18 @@ struct _cups_array_s // CUPS array structure static bool cups_array_add(cups_array_t *a, void *e, bool insert); static size_t cups_array_find(cups_array_t *a, void *e, size_t prev, int *rdiff); +static bool cups_array_multiply(size_t count, size_t size, size_t *bytes); + + +static bool cups_array_multiply(size_t count, size_t size, size_t *bytes) +{ + if (count > SIZE_MAX / size) + return (false); + + *bytes = count * size; + return (true); +} + // // 'cupsArrayAdd()' - Add an element to an array. @@ -280,8 +292,10 @@ cupsArrayDup(cups_array_t *a) // I - Array if (a->num_elements) { // Allocate memory for the elements... - da->elements = malloc((size_t)a->num_elements * sizeof(void *)); - if (!da->elements) + size_t bytes; + + if (!cups_array_multiply(a->num_elements, sizeof(void *), &bytes) || + (da->elements = malloc(bytes)) == NULL) { free(da); return (NULL); @@ -306,6 +320,23 @@ cupsArrayDup(cups_array_t *a) // I - Array da->alloc_elements = a->num_elements; } + /* Copy hash table if present so duplicated arrays preserve hashed lookups */ + if (a->hash) + { + size_t bytes; + + da->hashsize = a->hashsize; + if (!cups_array_multiply(da->hashsize, sizeof(size_t), &bytes) || + (da->hash = malloc(bytes)) == NULL) + { + if (da->elements) + free(da->elements); + free(da); + return (NULL); + } + memcpy(da->hash, a->hash, bytes); + } + // Return the new array... return (da); } @@ -653,17 +684,18 @@ cupsArrayNew(cups_array_cb_t f, // I - Comparison callback function or `NULL` f if (hsize > 0 && hf) { + size_t bytes; + a->hashfunc = hf; a->hashsize = hsize; - a->hash = malloc((size_t)hsize * sizeof(size_t)); - - if (!a->hash) + if (!cups_array_multiply(hsize, sizeof(size_t), &bytes) || + (a->hash = malloc(bytes)) == NULL) { free(a); return (NULL); } - memset(a->hash, -1, (size_t)hsize * sizeof(size_t)); + memset(a->hash, -1, bytes); } a->copyfunc = cf; @@ -863,7 +895,10 @@ cups_array_add(cups_array_t *a, // I - Array else count = a->alloc_elements + 1024; - if ((temp = realloc(a->elements, count * sizeof(void *))) == NULL) + size_t bytes; + + if (!cups_array_multiply(count, sizeof(void *), &bytes) || + (temp = realloc(a->elements, bytes)) == NULL) return (false); a->alloc_elements = count; diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 000000000..592eb072c --- /dev/null +++ b/tests/README.md @@ -0,0 +1,19 @@ +Test helper: cupsArrayDup + +Build and run (POSIX shell or MSYS2/WSL): + +```bash +cd path/to/libcups +# build the project first so headers and deps are available +./configure +make -j + +# then compile the test (from the project root) +gcc -I. tests/test_array_dup.c cups/array.c -o tests/test_array_dup + +# run +./tests/test_array_dup +``` + +On Windows with MSVC, compile the project with Visual Studio and link the test +against the built library, or run the test from within the project build. diff --git a/tests/test_array_dup.c b/tests/test_array_dup.c new file mode 100644 index 000000000..2610d98e0 --- /dev/null +++ b/tests/test_array_dup.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include "cups/array.h" + +// Simple hash: sum of bytes modulo size +static size_t +simple_hash(void *element, void *data) +{ + const char *s = (const char *)element; + size_t sum = 0; + + (void)data; + + for (; *s; s++) + sum += (unsigned char)*s; + + return (sum % ((size_t)data)); +} + +int main(void) +{ + const char *values[] = { "apple", "banana", "cherry", "date", "elderberry", NULL }; + cups_array_t *a, *d; + size_t i; + + // Create an array with hashing enabled (hash size 16). Use strdup/free for copy/free. + a = cupsArrayNew((cups_array_cb_t)strcmp, NULL, (cups_ahash_cb_t)simple_hash, 16, (cups_acopy_cb_t)strdup, (cups_afree_cb_t)free); + if (!a) + { + fprintf(stderr, "Failed to create array\n"); + return 2; + } + + for (i = 0; values[i]; i++) + { + if (!cupsArrayAdd(a, (void *)values[i])) + { + fprintf(stderr, "Failed to add %s\n", values[i]); + cupsArrayDelete(a); + return 3; + } + } + + // Duplicate the array + d = cupsArrayDup(a); + if (!d) + { + fprintf(stderr, "cupsArrayDup() failed\n"); + cupsArrayDelete(a); + return 4; + } + + // Verify all values can be found in the duplicate + for (i = 0; values[i]; i++) + { + void *found = cupsArrayFind(d, (void *)values[i]); + if (!found) + { + fprintf(stderr, "Value '%s' not found in duplicated array\n", values[i]); + cupsArrayDelete(a); + cupsArrayDelete(d); + return 5; + } + else + printf("Found '%s' in duplicate\n", (char *)found); + } + + cupsArrayDelete(a); + cupsArrayDelete(d); + + // Regression test for integer overflow protection in array allocation. + { + cups_array_t *bad = calloc(1, sizeof(cups_array_t)); + size_t bad_count = SIZE_MAX / sizeof(void *) + 1; + + if (!bad) + { + fprintf(stderr, "Failed to allocate array skeleton for overflow test\n"); + return 6; + } + + bad->num_elements = bad_count; + bad->elements = NULL; + bad->copyfunc = NULL; + bad->freefunc = NULL; + + if (cupsArrayDup(bad) != NULL) + { + fprintf(stderr, "cupsArrayDup() did not reject overflow count\n"); + free(bad); + return 7; + } + + free(bad); + } + + printf("Test passed\n"); + return 0; +}