From ee8f240f0cc9aa6aa74db6b32feb3cd719afdf0d Mon Sep 17 00:00:00 2001 From: Wei-Fan Chen Date: Thu, 27 Mar 2025 11:49:28 +0800 Subject: [PATCH] Hook realloc for test harness This commit implements test_realloc and makes it possible to adjust the memory size allocated by test_malloc() or test_calloc(). In this commit, there is still room for improvement. When we shrink the allocated memory size, we simply return the original array. This may lead to unused memory. Therefore, we can improve this in the future. Reference: https://danluu.com/malloc-tutorial/ Change-Id: Ic85b35cfff4dc0b6a46a6e81e6c1ce873625f0ac --- harness.c | 38 ++++++++++++++++++++++++++++++++++++++ harness.h | 3 ++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/harness.c b/harness.c index 4e02891f5..aa3240fb9 100644 --- a/harness.c +++ b/harness.c @@ -63,6 +63,7 @@ static bool time_limited = false; typedef enum { TEST_MALLOC, TEST_CALLOC, + TEST_REALLOC, } alloc_t; /* Internal functions */ @@ -128,6 +129,7 @@ static void *alloc(alloc_t alloc_type, size_t size) char *msg_alloc_forbidden[] = { "Calls to malloc are disallowed", "Calls to calloc are disallowed", + "Calls to realloc are disallowed", }; report_event(MSG_FATAL, "%s", msg_alloc_forbidden[alloc_type]); return NULL; @@ -137,6 +139,7 @@ static void *alloc(alloc_t alloc_type, size_t size) char *msg_alloc_failure[] = { "Malloc returning NULL", "Calloc returning NULL", + "Realloc returning NULL", }; report_event(MSG_WARN, "%s", msg_alloc_failure[alloc_type]); return NULL; @@ -187,6 +190,41 @@ void *test_calloc(size_t nelem, size_t elsize) return alloc(TEST_CALLOC, nelem * elsize); } +/* + * This function implements how to adjust the size of memory allocated + * by test_malloc or test_calloc. + * + * First, we check whether the memory is already allocated. + * If it wasn't allocated (p is NULL), + * the fucntion behaves like test_malloc, returning a newly allocated memory. + * + * Otherwise, we check the payload size of the orignal memory. + * - If new_size is less than or equal to it, return the original memory. + * - If new_size is greater than it, we allocate a new memory with new_size. + * Copy the contents from the orginal memory to the newly allocated memory + * ,and then free the original one. Finally, we return the newly one. + * + * Reference: https://danluu.com/malloc-tutorial + */ +void *test_realloc(void *p, size_t new_size) +{ + if (!p) + return alloc(TEST_REALLOC, new_size); + + const block_element_t *b = find_header(p); + if (b->payload_size >= new_size) + // TODO: Free some once we implement split. + return p; + + void *new_ptr = alloc(TEST_REALLOC, new_size); + if (!new_ptr) + return NULL; + memcpy(new_ptr, p, b->payload_size); + test_free(p); + + return new_ptr; +} + void test_free(void *p) { if (noallocate_mode) { diff --git a/harness.h b/harness.h index 3e2ccec40..69b67d445 100644 --- a/harness.h +++ b/harness.h @@ -12,9 +12,9 @@ void *test_malloc(size_t size); void *test_calloc(size_t nmemb, size_t size); +void *test_realloc(void *p, size_t new_size); void test_free(void *p); char *test_strdup(const char *s); -/* FIXME: provide test_realloc as well */ #ifdef INTERNAL @@ -56,6 +56,7 @@ void trigger_exception(char *msg); /* Tested program use our versions of malloc and free */ #define malloc test_malloc #define calloc test_calloc +#define realloc test_realloc #define free test_free /* Use undef to avoid strdup redefined error */