Sat, 24 May 2025 00:04:11 +0200
implement zalloc() - resolves #679
--- a/docs/Writerside/topics/allocator.h.md Fri May 23 14:00:24 2025 +0200 +++ b/docs/Writerside/topics/allocator.h.md Sat May 24 00:04:11 2025 +0200 @@ -23,6 +23,8 @@ void *cxMalloc(const CxAllocator *allocator, size_t n); +void *cxZalloc(const CxAllocator *allocator, size_t n); + void *cxCalloc(const CxAllocator *allocator, size_t nmemb, size_t size); @@ -38,7 +40,9 @@ void cxFree(const CxAllocator *allocator, void *mem); -int cx_reallocate(void **mem, size_t size); +void *cx_zalloc(size_t n); + +int cx_reallocate(void **mem, size_t n); int cx_reallocatearray(void **mem, size_t nmemb, size_t size); @@ -50,6 +54,7 @@ // Convenience macros that invokes above functions with the cxDefaultAllocator. #define cxMallocDefault(...) +#define cxZallocDefault(...) #define cxCallocDefault(...) #define cxReallocDefault(...) #define cxReallocateDefault(...) @@ -75,6 +80,9 @@ most prominently that invocations of `cxFree()` with a `NULL`-pointer for `mem` are ignored instead of causing segfault error. +The functions `cxZalloc()` and `cx_zalloc()` allocate memory and set every allocated byte to zero. +The latter is merely a macro for stdlibc `calloc(1,n)`. + Additionally, UCX provides the functions `cxReallocate()` and `cxReallocateArray()`, as well as their independent pendants `cx_reallocate()` and `cx_reallocatearray()`. All those functions solve the problem that a possible reallocation might fail,
--- a/src/allocator.c Fri May 23 14:00:24 2025 +0200 +++ b/src/allocator.c Sat May 24 00:04:11 2025 +0200 @@ -29,6 +29,7 @@ #include "cx/allocator.h" #include <errno.h> +#include <string.h> static void *cx_malloc_stdlib( cx_attr_unused void *d, @@ -116,6 +117,17 @@ return allocator->cl->malloc(allocator->data, n); } +void *cxZalloc( + const CxAllocator *allocator, + size_t n +) { + void *mem = allocator->cl->malloc(allocator->data, n); + if (mem != NULL) { + memset(mem, 0, n); + } + return mem; +} + void *cxRealloc( const CxAllocator *allocator, void *mem,
--- a/src/cx/allocator.h Fri May 23 14:00:24 2025 +0200 +++ b/src/cx/allocator.h Sat May 24 00:04:11 2025 +0200 @@ -228,6 +228,14 @@ cx_reallocatearray_((void**)(mem), nmemb, size) /** + * Allocates memory and sets every byte to zero. + * + * @param n (@c size_t) the number of bytes + * @return (@c void*) a pointer to the allocated memory + */ +#define cx_zalloc(n) calloc(1, n) + +/** * Free a block allocated by this allocator. * * @note Freeing a block of a different allocator is undefined. @@ -429,13 +437,33 @@ size_t size ); - +/** + * Allocate @p n bytes of memory and sets every byte to zero. + * + * @param allocator the allocator + * @param n the number of bytes + * @return a pointer to the allocated memory + */ +cx_attr_nodiscard +cx_attr_nonnull +cx_attr_malloc +cx_attr_dealloc_ucx +cx_attr_allocsize(2) +cx_attr_export +void *cxZalloc( + const CxAllocator *allocator, + size_t n +); /** * Convenience macro that invokes cxMalloc() with the cxDefaultAllocator. */ #define cxMallocDefault(...) cxMalloc(cxDefaultAllocator, __VA_ARGS__) /** + * Convenience macro that invokes cxZalloc() with the cxDefaultAllocator. + */ +#define cxZallocDefault(...) cxZalloc(cxDefaultAllocator, __VA_ARGS__) +/** * Convenience macro that invokes cxCalloc() with the cxDefaultAllocator. */ #define cxCallocDefault(...) cxCalloc(cxDefaultAllocator, __VA_ARGS__)
--- a/tests/test_allocator.c Fri May 23 14:00:24 2025 +0200 +++ b/tests/test_allocator.c Sat May 24 00:04:11 2025 +0200 @@ -46,6 +46,15 @@ cxFree(cxStdlibAllocator, test); } +CX_TEST(test_allocator_stdlib_zalloc) { + void *test = cxZalloc(cxStdlibAllocator, 16); + CX_TEST_DO { + CX_TEST_ASSERT(test != NULL); + CX_TEST_ASSERT(0 == memcmp(test, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)); + } + cxFree(cxStdlibAllocator, test); +} + CX_TEST(test_allocator_stdlib_calloc) { char *test = cxCalloc(cxStdlibAllocator, 8, 2); CX_TEST_DO { @@ -110,6 +119,15 @@ cxFreeDefault(test); } +CX_TEST(test_allocator_default_zalloc) { + void *test = cxZallocDefault(16); + CX_TEST_DO { + CX_TEST_ASSERT(test != NULL); + CX_TEST_ASSERT(0 == memcmp(test, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)); + } + cxFreeDefault(test); +} + CX_TEST(test_allocator_default_calloc) { char *test = cxCallocDefault(8, 2); CX_TEST_DO { @@ -270,12 +288,14 @@ CxTestSuite *suite = cx_test_suite_new("allocator"); cx_test_register(suite, test_allocator_stdlib_malloc); + cx_test_register(suite, test_allocator_stdlib_zalloc); cx_test_register(suite, test_allocator_stdlib_calloc); cx_test_register(suite, test_allocator_stdlib_realloc); cx_test_register(suite, test_allocator_stdlib_reallocarray); cx_test_register(suite, test_allocator_stdlib_reallocarray_overflow); cx_test_register(suite, test_allocator_stdlib_free); cx_test_register(suite, test_allocator_default_malloc); + cx_test_register(suite, test_allocator_default_zalloc); cx_test_register(suite, test_allocator_default_calloc); cx_test_register(suite, test_allocator_default_realloc); cx_test_register(suite, test_allocator_default_reallocarray);