/** * @file test_random.c * @brief Randomized correctness test for malloc/free/realloc. * * 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_test_realloc (const char *label, size_t min, size_t max, int seed, int base_index, int count) { void *blocks[count]; size_t sizes[count]; size_t new_size; size_t check_size; 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]) { 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; } new_size = _s_rand_range (min, max); blocks[i] = realloc (blocks[i], new_size); if (!blocks[i]) { _s_put_str (label); _s_put_str ("["); _s_put_nbr (i); _s_put_str ("]: realloc FAILED\n"); fail = 1; i++; continue; } check_size = sizes[i]; if (new_size < check_size) check_size = new_size; data = (unsigned char *)blocks[i]; j = 0; while (j < (int)check_size) { 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)check_size) { _s_put_str (label); _s_put_str ("["); _s_put_nbr (i); _s_put_str ("]: OK ("); _s_put_nbr ((int)sizes[i]); _s_put_str (" -> "); _s_put_nbr ((int)new_size); _s_put_str (" bytes)\n"); } sizes[i] = new_size; 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); fail |= _s_test_realloc ("REALLOC_TINY", 1, TINY_MAX, seed, count * 3, count); fail |= _s_test_realloc ("REALLOC_SMALL", TINY_MAX + 1, SMALL_MAX, seed, count * 4, count); fail |= _s_test_realloc ("REALLOC_LARGE", SMALL_MAX + 1, LARGE_MAX, seed, count * 5, count); return (fail); }