1#include "alloc.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <assert.h>
6#include <stdint.h>
7#include <stdbool.h>
8
9static uint32_t g_rng = 0x12345678;
10
11static uint32_t my_rand(void) {
12 g_rng ^= g_rng << 13;
13 g_rng ^= g_rng >> 17;
14 g_rng ^= g_rng << 5;
15 return g_rng;
16}
17
18static void fill_pattern(uint8_t *ptr, size_t size, uint32_t seed) {
19 for (size_t i = 0; i < size; i++) {
20 ptr[i] = (uint8_t)((seed + i) & 0xFF);
21 }
22}
23
24static bool verify_pattern(const uint8_t *ptr, size_t size, uint32_t seed) {
25 for (size_t i = 0; i < size; i++) {
26 if (ptr[i] != (uint8_t)((seed + i) & 0xFF)) {
27 return false;
28 }
29 }
30 return true;
31}
32
33static void test_basic_and_alignment(void) {
34 printf("[TEST] Running basic and alignment tests...\n");
35 my_init();
36 assert(my_heap_check());
37
38
39 assert(my_malloc(0) == NULL);
40
41
42 my_free(NULL);
43
44
45 size_t test_sizes[] = {1, 3, 7, 15, 16, 17, 31, 32, 64, 100, 255, 512, 1024, 4096};
46 void *ptrs[14];
47 for (size_t i = 0; i < 14; i++) {
48 ptrs[i] = my_malloc(test_sizes[i]);
49 assert(ptrs[i] != NULL);
50 assert(((uintptr_t)ptrs[i] % 16) == 0);
51 fill_pattern((uint8_t *)ptrs[i], test_sizes[i], (uint32_t)i);
52 }
53
54 assert(my_heap_check());
55
56 for (size_t i = 0; i < 14; i++) {
57 assert(verify_pattern((const uint8_t *)ptrs[i], test_sizes[i], (uint32_t)i));
58 my_free(ptrs[i]);
59 }
60
61 assert(my_heap_check());
62 stats_t st;
63 my_stats(&st);
64 assert(st.bytes_in_use == 0);
65 assert(st.free_block_count == 1);
66 printf(" -> Basic & Alignment tests PASSED.\n");
67}
68
69static void test_calloc(void) {
70 printf("[TEST] Running my_calloc tests...\n");
71 my_init();
72
73 size_t count = 128;
74 size_t elem_size = sizeof(int);
75 int *arr = (int *)my_calloc(count, elem_size);
76 assert(arr != NULL);
77 assert(((uintptr_t)arr % 16) == 0);
78
79 for (size_t i = 0; i < count; i++) {
80 assert(arr[i] == 0);
81 }
82
83 assert(my_heap_check());
84 my_free(arr);
85 assert(my_heap_check());
86 printf(" -> my_calloc tests PASSED.\n");
87}
88
89static void test_fragmentation_and_coalescing(void) {
90 printf("[TEST] Running fragmentation & coalescing scenario tests...\n");
91 my_init();
92
93 stats_t init_st;
94 my_stats(&init_st);
95 size_t max_payload = init_st.largest_free_block;
96 assert(init_st.free_block_count == 1);
97
98 #define NUM_BLOCKS 50
99 void *blocks[NUM_BLOCKS];
100 size_t blk_size = 2048;
101
102 for (int i = 0; i < NUM_BLOCKS; i++) {
103 blocks[i] = my_malloc(blk_size);
104 assert(blocks[i] != NULL);
105 fill_pattern((uint8_t *)blocks[i], blk_size, (uint32_t)i);
106 }
107
108 assert(my_heap_check());
109
110
111 for (int i = 0; i < NUM_BLOCKS; i += 2) {
112 assert(verify_pattern((const uint8_t *)blocks[i], blk_size, (uint32_t)i));
113 my_free(blocks[i]);
114 blocks[i] = NULL;
115 }
116
117 assert(my_heap_check());
118 stats_t frag_st;
119 my_stats(&frag_st);
120 assert(frag_st.free_block_count > 1);
121
122
123 for (int i = 1; i < NUM_BLOCKS; i += 2) {
124 assert(verify_pattern((const uint8_t *)blocks[i], blk_size, (uint32_t)i));
125 my_free(blocks[i]);
126 blocks[i] = NULL;
127 }
128
129
130 assert(my_heap_check());
131 stats_t end_st;
132 my_stats(&end_st);
133 assert(end_st.bytes_in_use == 0);
134 assert(end_st.free_block_count == 1);
135 assert(end_st.largest_free_block == max_payload);
136
137
138 void *a = my_malloc(1024);
139 void *b = my_malloc(1024);
140 void *c = my_malloc(1024);
141 assert(a && b && c);
142
143 my_free(b);
144 assert(my_heap_check());
145 my_free(a);
146 assert(my_heap_check());
147 my_free(c);
148 assert(my_heap_check());
149
150 my_stats(&end_st);
151 assert(end_st.bytes_in_use == 0);
152 assert(end_st.free_block_count == 1);
153 assert(end_st.largest_free_block == max_payload);
154
155 printf(" -> Fragmentation & coalescing tests PASSED.\n");
156 #undef NUM_BLOCKS
157}
158
159static void test_canary_violation(void) {
160 printf("[TEST] Running canary-violation detection tests...\n");
161 my_init();
162
163 void *p = my_malloc(64);
164 assert(p != NULL);
165 assert(my_heap_check() == true);
166
167
168 uint32_t *hdr_canary = (uint32_t *)((char *)p - 48);
169 uint32_t orig_val = *hdr_canary;
170 *hdr_canary = 0xBADBAD00;
171
172
173 assert(my_heap_check() == false);
174
175
176 *hdr_canary = orig_val;
177 assert(my_heap_check() == true);
178
179
180
181
182 uint32_t *ftr_canary = (uint32_t *)((char *)p + 64);
183 uint32_t orig_ftr_val = *ftr_canary;
184 *ftr_canary = 0xDEAD0000;
185
186 assert(my_heap_check() == false);
187
188
189 my_init();
190 assert(my_heap_check() == true);
191 printf(" -> Canary-violation tests PASSED.\n");
192}
193
194#define SHADOW_CAP 2000
195#define STRESS_OPS 100000
196
197typedef struct {
198 void *ptr;
199 size_t size;
200 uint32_t seed;
201 bool active;
202} shadow_slot_t;
203
204static shadow_slot_t g_slots[SHADOW_CAP];
205static int g_active_indices[SHADOW_CAP];
206static int g_active_count = 0;
207
208static void test_seeded_stress(void) {
209 printf("[TEST] Running 100k seeded stress test...\n");
210 my_init();
211 g_rng = 0xA5A5A5A5;
212
213 memset(g_slots, 0, sizeof(g_slots));
214 g_active_count = 0;
215
216 for (int op = 0; op < STRESS_OPS; op++) {
217 uint32_t roll = my_rand() % 100;
218
219 if (roll < 45) {
220
221 if (g_active_count < SHADOW_CAP) {
222 size_t sz = 1 + (my_rand() % 2048);
223 void *ptr = my_malloc(sz);
224 if (ptr != NULL) {
225 assert(((uintptr_t)ptr % 16) == 0);
226 uint32_t sd = my_rand();
227
228
229 int slot_idx = -1;
230 for (int i = 0; i < SHADOW_CAP; i++) {
231 if (!g_slots[i].active) {
232 slot_idx = i;
233 break;
234 }
235 }
236 assert(slot_idx != -1);
237
238 g_slots[slot_idx].ptr = ptr;
239 g_slots[slot_idx].size = sz;
240 g_slots[slot_idx].seed = sd;
241 g_slots[slot_idx].active = true;
242
243 fill_pattern((uint8_t *)ptr, sz, sd);
244
245 g_active_indices[g_active_count++] = slot_idx;
246 }
247 }
248 } else if (roll < 85) {
249
250 if (g_active_count > 0) {
251 int pick = my_rand() % g_active_count;
252 int slot_idx = g_active_indices[pick];
253
254 assert(g_slots[slot_idx].active);
255 assert(verify_pattern((const uint8_t *)g_slots[slot_idx].ptr, g_slots[slot_idx].size, g_slots[slot_idx].seed));
256
257 my_free(g_slots[slot_idx].ptr);
258 g_slots[slot_idx].active = false;
259
260 g_active_indices[pick] = g_active_indices[g_active_count - 1];
261 g_active_count--;
262 }
263 } else {
264
265 if (g_active_count > 0) {
266 int pick = my_rand() % g_active_count;
267 int slot_idx = g_active_indices[pick];
268
269 assert(g_slots[slot_idx].active);
270 assert(verify_pattern((const uint8_t *)g_slots[slot_idx].ptr, g_slots[slot_idx].size, g_slots[slot_idx].seed));
271
272 size_t new_sz = 1 + (my_rand() % 2048);
273 uint32_t new_sd = my_rand();
274
275 void *new_ptr = my_realloc(g_slots[slot_idx].ptr, new_sz);
276 if (new_ptr != NULL) {
277 assert(((uintptr_t)new_ptr % 16) == 0);
278 g_slots[slot_idx].ptr = new_ptr;
279 g_slots[slot_idx].size = new_sz;
280 g_slots[slot_idx].seed = new_sd;
281
282 fill_pattern((uint8_t *)new_ptr, new_sz, new_sd);
283 }
284 }
285 }
286
287 if ((op + 1) % 25000 == 0) {
288 assert(my_heap_check() == true);
289 printf(" -> Progress: %d / %d operations complete...\n", op + 1, STRESS_OPS);
290 }
291 }
292
293 assert(my_heap_check() == true);
294
295
296 for (int i = 0; i < g_active_count; i++) {
297 int slot_idx = g_active_indices[i];
298 assert(g_slots[slot_idx].active);
299 assert(verify_pattern((const uint8_t *)g_slots[slot_idx].ptr, g_slots[slot_idx].size, g_slots[slot_idx].seed));
300 my_free(g_slots[slot_idx].ptr);
301 g_slots[slot_idx].active = false;
302 }
303 g_active_count = 0;
304
305 assert(my_heap_check() == true);
306 stats_t final_st;
307 my_stats(&final_st);
308 assert(final_st.bytes_in_use == 0);
309 assert(final_st.free_block_count == 1);
310
311 printf(" -> 100k Seeded Stress test PASSED.\n");
312}
313
314int main(void) {
315 printf("=== RUNNING MEMORY ALLOCATOR TEST SUITE ===\n\n");
316 test_basic_and_alignment();
317 test_calloc();
318 test_fragmentation_and_coalescing();
319 test_canary_violation();
320 test_seeded_stress();
321 printf("\n=== ALL TESTS PASSED CLEANLY! ===\n");
322 return 0;
323}
324
Discussion
No comments yet. Start the discussion. Recorded by @patrick-toulme.