• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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