From b8de4f339318dc245b073f05e186c4b2b1e8e758 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Fri, 27 Feb 2026 11:57:42 +0100 Subject: Add randomized correctness test test_random allocates N blocks per category (TINY/SMALL/LARGE) with random sizes, fills them with a deterministic pattern, and verifies the data. Run with system malloc and LD_PRELOAD to compare output. Seed and count are parameterized via argv. --- tests/Makefile | 17 ++++- tests/src/test_random.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 tests/src/test_random.c (limited to 'tests') diff --git a/tests/Makefile b/tests/Makefile index b964db5..28a9741 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -7,6 +7,7 @@ BINDIR = bin NAME_PRELOAD = $(BINDIR)/test_preload NAME_SHOW = $(BINDIR)/test_show +NAME_RANDOM = $(BINDIR)/test_random SRCS = test_preload.c @@ -24,7 +25,10 @@ $(NAME_SHOW): $(OBJDIR)/test_show.o $(MALLOC_LIB) | $(BINDIR) $(OBJDIR)/test_show.o: $(SRCDIR)/test_show.c | $(OBJDIR) $(CC) $(CFLAGS) -I $(MALLOC_INC) -c $< -o $@ -all: $(NAME_PRELOAD) $(NAME_SHOW) +$(NAME_RANDOM): $(OBJDIR)/test_random.o | $(BINDIR) + $(CC) $(CFLAGS) -o $@ $(OBJDIR)/test_random.o + +all: $(NAME_PRELOAD) $(NAME_SHOW) $(NAME_RANDOM) $(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ @@ -35,7 +39,10 @@ $(OBJDIR): $(BINDIR): mkdir -p $(BINDIR) -test: $(NAME_PRELOAD) $(NAME_SHOW) +SEED ?= 42 +COUNT ?= 10 + +test: $(NAME_PRELOAD) $(NAME_SHOW) $(NAME_RANDOM) @echo "=== system malloc ===" @$(NAME_PRELOAD) @echo "" @@ -44,6 +51,12 @@ test: $(NAME_PRELOAD) $(NAME_SHOW) @echo "" @echo "=== show_alloc_mem ===" @$(NAME_SHOW) + @echo "" + @echo "=== random (system, seed=$(SEED) count=$(COUNT)) ===" + @$(NAME_RANDOM) $(SEED) $(COUNT) + @echo "" + @echo "=== random (ft_malloc, seed=$(SEED) count=$(COUNT)) ===" + @LD_PRELOAD=$(MALLOC_LIB) $(NAME_RANDOM) $(SEED) $(COUNT) clean: rm -rf $(OBJDIR) $(BINDIR) diff --git a/tests/src/test_random.c b/tests/src/test_random.c new file mode 100644 index 0000000..f7247e2 --- /dev/null +++ b/tests/src/test_random.c @@ -0,0 +1,176 @@ +/** + * @file test_random.c + * @brief Randomized correctness test for malloc/free. + * + * Allocates random-sized blocks in TINY, SMALL, and LARGE ranges, + * fills them with a deterministic pattern, then verifies the data. + * Run with system malloc and LD_PRELOAD — output must match. + * + * Usage: test_random + */ + +#include +#include + +#define TINY_MAX 128 +#define SMALL_MAX 1024 +#define LARGE_MAX 8192 + +static void +_s_put_str (const char *str) +{ + const char *p; + + p = str; + while (*p) + p++; + write (1, str, (size_t)(p - str)); +} + +static void +_s_put_nbr (int n) +{ + char buf[12]; + int i; + + i = (int)sizeof (buf); + if (n == 0) + buf[--i] = '0'; + while (n > 0) + { + buf[--i] = '0' + (n % 10); + n /= 10; + } + write (1, buf + i, (size_t)(sizeof (buf) - i)); +} + +static unsigned char +_s_pattern (int seed, int alloc_index, int byte_index) +{ + return ((unsigned char)((seed * 31 + alloc_index * 7 + byte_index) & 0xFF)); +} + +static size_t +_s_rand_range (size_t min, size_t max) +{ + return (min + (size_t)rand () % (max - min + 1)); +} + +static int +_s_test_category (const char *label, size_t min, size_t max, int seed, + int base_index, int count) +{ + void *blocks[count]; + size_t sizes[count]; + unsigned char *data; + int fail; + int i; + int j; + + fail = 0; + i = 0; + while (i < count) + { + sizes[i] = _s_rand_range (min, max); + blocks[i] = malloc (sizes[i]); + if (!blocks[i]) + { + _s_put_str (label); + _s_put_str ("["); + _s_put_nbr (i); + _s_put_str ("]: malloc FAILED\n"); + fail = 1; + i++; + continue; + } + data = (unsigned char *)blocks[i]; + j = 0; + while (j < (int)sizes[i]) + { + data[j] = _s_pattern (seed, base_index + i, j); + j++; + } + i++; + } + i = 0; + while (i < count) + { + if (!blocks[i]) + { + i++; + continue; + } + data = (unsigned char *)blocks[i]; + j = 0; + while (j < (int)sizes[i]) + { + if (data[j] != _s_pattern (seed, base_index + i, j)) + { + _s_put_str (label); + _s_put_str ("["); + _s_put_nbr (i); + _s_put_str ("]: FAIL at byte "); + _s_put_nbr (j); + _s_put_str ("\n"); + fail = 1; + break; + } + j++; + } + if (j == (int)sizes[i]) + { + _s_put_str (label); + _s_put_str ("["); + _s_put_nbr (i); + _s_put_str ("]: OK ("); + _s_put_nbr ((int)sizes[i]); + _s_put_str (" bytes)\n"); + } + i++; + } + i = 0; + while (i < count) + { + free (blocks[i]); + i++; + } + return (fail); +} + +static int +_s_atoi (const char *str) +{ + int n; + + n = 0; + while (*str) + { + n = n * 10 + (*str - '0'); + str++; + } + return (n); +} + +int +main (int argc, char **argv) +{ + int seed; + int count; + int fail; + + if (argc != 3) + { + _s_put_str ("usage: test_random \n"); + return (1); + } + seed = _s_atoi (argv[1]); + count = _s_atoi (argv[2]); + srand ((unsigned int)seed); + fail = 0; + fail |= _s_test_category ("TINY", 1, TINY_MAX, seed, 0, count); + fail |= _s_test_category ("SMALL", TINY_MAX + 1, SMALL_MAX, seed, count, + count); + fail |= _s_test_category ("LARGE", SMALL_MAX + 1, LARGE_MAX, seed, count * 2, + count); + return (fail); +} -- cgit v1.2.3