1 /* ==========================================
2 * Unity Project - A Test Framework for C
3 * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
4 * [Released under MIT License. Please refer to license.txt for details]
5 * ========================================== */
6
7 #include "unity.h"
8 #include "unity_memory.h"
9 #include <string.h>
10
11 #define MALLOC_DONT_FAIL -1
12 static int malloc_count;
13 static int malloc_fail_countdown = MALLOC_DONT_FAIL;
14
UnityMalloc_StartTest(void)15 void UnityMalloc_StartTest(void)
16 {
17 malloc_count = 0;
18 malloc_fail_countdown = MALLOC_DONT_FAIL;
19 }
20
UnityMalloc_EndTest(void)21 void UnityMalloc_EndTest(void)
22 {
23 malloc_fail_countdown = MALLOC_DONT_FAIL;
24 if (malloc_count != 0)
25 {
26 UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "This test leaks!");
27 }
28 }
29
UnityMalloc_MakeMallocFailAfterCount(int countdown)30 void UnityMalloc_MakeMallocFailAfterCount(int countdown)
31 {
32 malloc_fail_countdown = countdown;
33 }
34
35 /* These definitions are always included from unity_fixture_malloc_overrides.h */
36 /* We undef to use them or avoid conflict with <stdlib.h> per the C standard */
37 #undef malloc
38 #undef free
39 #undef calloc
40 #undef realloc
41
42 #ifdef UNITY_EXCLUDE_STDLIB_MALLOC
43 static unsigned char unity_heap[UNITY_INTERNAL_HEAP_SIZE_BYTES];
44 static size_t heap_index;
45 #else
46 #include <stdlib.h>
47 #endif
48
49 typedef struct GuardBytes
50 {
51 size_t size;
52 size_t guard_space;
53 } Guard;
54
55 #define UNITY_MALLOC_ALIGNMENT (UNITY_POINTER_WIDTH / 8)
56 static const char end[] = "END";
57
unity_size_round_up(size_t size)58 static size_t unity_size_round_up(size_t size)
59 {
60 size_t rounded_size;
61
62 rounded_size = ((size + UNITY_MALLOC_ALIGNMENT - 1) / UNITY_MALLOC_ALIGNMENT) * UNITY_MALLOC_ALIGNMENT;
63
64 return rounded_size;
65 }
66
unity_malloc(size_t size)67 void* unity_malloc(size_t size)
68 {
69 char* mem;
70 Guard* guard;
71 size_t total_size;
72
73 total_size = sizeof(Guard) + unity_size_round_up(size + sizeof(end));
74
75 if (malloc_fail_countdown != MALLOC_DONT_FAIL)
76 {
77 if (malloc_fail_countdown == 0)
78 return NULL;
79 malloc_fail_countdown--;
80 }
81
82 if (size == 0) return NULL;
83 #ifdef UNITY_EXCLUDE_STDLIB_MALLOC
84 if (heap_index + total_size > UNITY_INTERNAL_HEAP_SIZE_BYTES)
85 {
86 guard = NULL;
87 }
88 else
89 {
90 /* We know we can get away with this cast because we aligned memory already */
91 guard = (Guard*)(void*)(&unity_heap[heap_index]);
92 heap_index += total_size;
93 }
94 #else
95 guard = (Guard*)UNITY_MALLOC(total_size);
96 #endif
97 if (guard == NULL) return NULL;
98 malloc_count++;
99 guard->size = size;
100 guard->guard_space = 0;
101 mem = (char*)&(guard[1]);
102 memcpy(&mem[size], end, sizeof(end));
103
104 return (void*)mem;
105 }
106
isOverrun(void * mem)107 static int isOverrun(void* mem)
108 {
109 Guard* guard = (Guard*)mem;
110 char* memAsChar = (char*)mem;
111 guard--;
112
113 return guard->guard_space != 0 || strcmp(&memAsChar[guard->size], end) != 0;
114 }
115
release_memory(void * mem)116 static void release_memory(void* mem)
117 {
118 Guard* guard = (Guard*)mem;
119 guard--;
120
121 malloc_count--;
122 #ifdef UNITY_EXCLUDE_STDLIB_MALLOC
123 {
124 size_t block_size;
125
126 block_size = unity_size_round_up(guard->size + sizeof(end));
127
128 if (mem == unity_heap + heap_index - block_size)
129 {
130 heap_index -= (sizeof(Guard) + block_size);
131 }
132 }
133 #else
134 UNITY_FREE(guard);
135 #endif
136 }
137
unity_free(void * mem)138 void unity_free(void* mem)
139 {
140 int overrun;
141
142 if (mem == NULL)
143 {
144 return;
145 }
146
147 overrun = isOverrun(mem);
148 release_memory(mem);
149 if (overrun)
150 {
151 UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during free()");
152 }
153 }
154
unity_calloc(size_t num,size_t size)155 void* unity_calloc(size_t num, size_t size)
156 {
157 void* mem = unity_malloc(num * size);
158 if (mem == NULL) return NULL;
159 memset(mem, 0, num * size);
160 return mem;
161 }
162
unity_realloc(void * oldMem,size_t size)163 void* unity_realloc(void* oldMem, size_t size)
164 {
165 Guard* guard = (Guard*)oldMem;
166 void* newMem;
167
168 if (oldMem == NULL) return unity_malloc(size);
169
170 guard--;
171 if (isOverrun(oldMem))
172 {
173 release_memory(oldMem);
174 UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during realloc()");
175 }
176
177 if (size == 0)
178 {
179 release_memory(oldMem);
180 return NULL;
181 }
182
183 if (guard->size >= size) return oldMem;
184
185 #ifdef UNITY_EXCLUDE_STDLIB_MALLOC /* Optimization if memory is expandable */
186 {
187 size_t old_total_size = unity_size_round_up(guard->size + sizeof(end));
188
189 if ((oldMem == unity_heap + heap_index - old_total_size) &&
190 ((heap_index - old_total_size + unity_size_round_up(size + sizeof(end))) <= UNITY_INTERNAL_HEAP_SIZE_BYTES))
191 {
192 release_memory(oldMem); /* Not thread-safe, like unity_heap generally */
193 return unity_malloc(size); /* No memcpy since data is in place */
194 }
195 }
196 #endif
197 newMem = unity_malloc(size);
198 if (newMem == NULL) return NULL; /* Do not release old memory */
199 memcpy(newMem, oldMem, guard->size);
200 release_memory(oldMem);
201 return newMem;
202 }
203