1#include "alloc.h"
2
3#include <stdint.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#define CHECK(cond) do { \
9 if (!(cond)) { \
10 fprintf(stderr, "CHECK failed at %s:%d: %s\n", __FILE__, __LINE__, #cond); \
11 exit(1); \
12 } \
13} while (0)
14
15#define SLOTS 1024
16#define OPS 100000
17
18typedef struct shadow {
19 unsigned char *ptr;
20 size_t size;
21 unsigned char pat;
22} shadow_t;
23
24static uint32_t rng_state = 0xC0FFEEu;
25static uint32_t rnd(void) {
26 rng_state = rng_state * 1664525u + 1013904223u;
27 return rng_state;
28}
29
30static void fill_shadow(shadow_t *s) {
31 if (s->ptr && s->size) memset(s->ptr, s->pat, s->size);
32}
33
34static void verify_shadow(const shadow_t *s) {
35 if (!s->ptr) return;
36 for (size_t i = 0; i < s->size; i++) {
37 if (s->ptr[i] != s->pat) {
38 fprintf(stderr, "pattern mismatch at byte %zu (got %u want %u)\n",
39 i, (unsigned)s->ptr[i], (unsigned)s->pat);
40 exit(1);
41 }
42 }
43}
44
45static void stress_test(void) {
46 shadow_t slots[SLOTS];
47 memset(slots, 0, sizeof(slots));
48
49 for (int op = 0; op < OPS; op++) {
50 size_t idx = rnd() % SLOTS;
51 shadow_t *s = &slots[idx];
52 uint32_t choice = rnd() % 100;
53
54 if (choice < 45) {
55 if (s->ptr) {
56 verify_shadow(s);
57 my_free(s->ptr);
58 s->ptr = NULL;
59 s->size = 0;
60 } else {
61 size_t n = (rnd() % 4096u) + 1u;
62 unsigned char *p = my_malloc(n);
63 if (p) {
64 CHECK(((uintptr_t)p & 15u) == 0);
65 s->ptr = p;
66 s->size = n;
67 s->pat = (unsigned char)(idx ^ op ^ 0xA5u);
68 fill_shadow(s);
69 }
70 }
71 } else if (choice < 75) {
72 size_t n = (rnd() % 8192u) + 1u;
73 if (s->ptr) verify_shadow(s);
74 unsigned char *old = s->ptr;
75 unsigned char *p = my_realloc(s->ptr, n);
76 if (p) {
77 CHECK(((uintptr_t)p & 15u) == 0);
78 s->ptr = p;
79 s->size = n;
80 s->pat = (unsigned char)(idx ^ op ^ 0x5Au);
81 fill_shadow(s);
82 } else if (old) {
83
84 verify_shadow(s);
85 }
86 } else {
87 verify_shadow(s);
88 }
89
90 if ((op % 1000) == 0) CHECK(my_heap_check());
91 }
92
93 for (size_t i = 0; i < SLOTS; i++) {
94 if (slots[i].ptr) {
95 verify_shadow(&slots[i]);
96 my_free(slots[i].ptr);
97 }
98 }
99 CHECK(my_heap_check());
100 my_stats_t st = my_stats();
101 CHECK(st.bytes_in_use == 0);
102 CHECK(st.free_block_count == 1);
103}
104
105static void fragmentation_test(void) {
106 CHECK(my_heap_check());
107 my_stats_t before = my_stats();
108 size_t full = before.largest_free_block;
109
110 void *a = my_malloc(20000);
111 void *b = my_malloc(30000);
112 void *c = my_malloc(40000);
113 CHECK(a && b && c);
114 CHECK(my_heap_check());
115
116 my_free(b);
117 CHECK(my_heap_check());
118 my_stats_t mid = my_stats();
119 CHECK(mid.free_block_count == 2);
120 CHECK(mid.largest_free_block < full);
121
122 my_free(a);
123 my_free(c);
124 CHECK(my_heap_check());
125 my_stats_t after = my_stats();
126 CHECK(after.bytes_in_use == 0);
127 CHECK(after.free_block_count == 1);
128 CHECK(after.largest_free_block == full);
129}
130
131static void canary_violation_test(void) {
132 unsigned char *p = my_malloc(32);
133 CHECK(p != NULL);
134 CHECK(my_heap_check());
135 uint64_t *footer = (uint64_t *)(void *)(p + 32);
136 *footer ^= UINT64_C(0x12345678);
137 CHECK(!my_heap_check());
138}
139
140int main(void) {
141 stress_test();
142 fragmentation_test();
143 canary_violation_test();
144 puts("all tests passed");
145 return 0;
146}
147
Discussion
No comments yet. Start the discussion. Recorded by @patrick-toulme.