blob: c7df7b4111560e06043eaa537a0200b7951db6b2 [file] [log] [blame]
Paul Bakker6e339b52013-07-03 13:37:05 +02001/*
2 * Buffer-based memory allocator
3 *
4 * Copyright (C) 2006-2013, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#include "polarssl/config.h"
27
28#if defined(POLARSSL_MEMORY_C) && defined(POLARSSL_MEMORY_BUFFER_ALLOC_C)
29
30#include "polarssl/memory.h"
31
32#include <string.h>
33
34#if defined(POLARSSL_MEMORY_DEBUG)
35#include <stdio.h>
36#if defined(POLARSSL_MEMORY_BACKTRACE)
37#include <execinfo.h>
38#endif
39#endif
40
41#define MAGIC1 0xFF00AA55
42#define MAGIC2 0xEE119966
43#define MAX_BT 20
44
45typedef struct _memory_header memory_header;
46struct _memory_header
47{
48 size_t magic1;
49 size_t size;
50 size_t alloc;
51 memory_header *prev;
52 memory_header *next;
53#if defined(POLARSSL_MEMORY_BACKTRACE)
54 char **trace;
55 size_t trace_count;
56#endif
57 size_t magic2;
58};
59
60typedef struct
61{
62 unsigned char *buf;
63 size_t len;
64 memory_header *first;
65 size_t largest_free;
66 size_t current_alloc_size;
67 int verify;
68}
69buffer_alloc_ctx;
70
71static buffer_alloc_ctx heap;
72
73#if defined(POLARSSL_MEMORY_DEBUG)
74static void debug_header( memory_header *hdr )
75{
76#if defined(POLARSSL_MEMORY_BACKTRACE)
77 size_t i;
78#endif
79
80 fprintf(stderr, "HDR: PTR(%10u), PREV(%10u), NEXT(%10u), ALLOC(%u), SIZE(%10u)\n",
81 (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next,
82 hdr->alloc, hdr->size );
83
84#if defined(POLARSSL_MEMORY_BACKTRACE)
85 fprintf(stderr, "TRACE: \n");
86 for( i = 0; i < hdr->trace_count; i++ )
87 fprintf(stderr, "%s\n", hdr->trace[i]);
88#endif
89}
90
91static void debug_chain()
92{
93 memory_header *cur = heap.first;
94
95 while( cur != NULL )
96 {
97 debug_header( cur );
98 fprintf(stderr, "\n");
99 cur = cur->next;
100 }
101}
102#endif /* POLARSSL_MEMORY_DEBUG */
103
104static int verify_header( memory_header *hdr )
105{
106 if( hdr->magic1 != MAGIC1 )
107 {
108#if defined(POLARSSL_MEMORY_DEBUG)
109 fprintf(stderr, "FATAL: MAGIC1 mismatch\n");
110#endif
111 return( 1 );
112 }
113
114 if( hdr->magic2 != MAGIC2 )
115 {
116#if defined(POLARSSL_MEMORY_DEBUG)
117 fprintf(stderr, "FATAL: MAGIC2 mismatch\n");
118#endif
119 return( 1 );
120 }
121
122 if( hdr->alloc > 1 )
123 {
124#if defined(POLARSSL_MEMORY_DEBUG)
125 fprintf(stderr, "FATAL: alloc has illegal value\n");
126#endif
127 return( 1 );
128 }
129
130 return( 0 );
131}
132
133static int verify_chain()
134{
135 memory_header *prv = heap.first, *cur = heap.first->next;
136
137 if( verify_header( heap.first ) != 0 )
138 {
139#if defined(POLARSSL_MEMORY_DEBUG)
140 fprintf(stderr, "FATAL: verification of first header failed\n");
141#endif
142 return( 1 );
143 }
144
145 if( heap.first->prev != NULL )
146 {
147#if defined(POLARSSL_MEMORY_DEBUG)
148 fprintf(stderr, "FATAL: verification failed: first->prev != NULL\n");
149#endif
150 return( 1 );
151 }
152
153 while( cur != NULL )
154 {
155 if( verify_header( cur ) != 0 )
156 {
157#if defined(POLARSSL_MEMORY_DEBUG)
158 fprintf(stderr, "FATAL: verification of header failed\n");
159#endif
160 return( 1 );
161 }
162
163 if( cur->prev != prv )
164 {
165#if defined(POLARSSL_MEMORY_DEBUG)
166 fprintf(stderr, "FATAL: verification failed: cur->prev != prv\n");
167#endif
168 return( 1 );
169 }
170
171 prv = cur;
172 cur = cur->next;
173 }
174
175 return( 0 );
176}
177
178static void *buffer_alloc_malloc( size_t len )
179{
180 memory_header *new, *cur = heap.first;
181 unsigned char *p;
182#if defined(POLARSSL_MEMORY_BACKTRACE)
183 void *trace_buffer[MAX_BT];
184 size_t trace_cnt;
185#endif
186
187 if( heap.buf == NULL || heap.first == NULL )
188 return( NULL );
189
190 if( len % POLARSSL_MEMORY_ALIGN_MULTIPLE )
191 {
192 len -= len % POLARSSL_MEMORY_ALIGN_MULTIPLE;
193 len += POLARSSL_MEMORY_ALIGN_MULTIPLE;
194 }
195
196 // Find block that fits
197 //
198 while( cur != NULL )
199 {
200 if( cur->alloc == 0 && cur->size >= len )
201 break;
202
203 cur = cur->next;
204 }
205
206 if( cur == NULL )
207 return( NULL );
208
209 // Found location, split block if > memory_header + 4 room left
210 //
211 if( cur->size - len < sizeof(memory_header) + POLARSSL_MEMORY_ALIGN_MULTIPLE )
212 {
213 cur->alloc = 1;
214
215#if defined(POLARSSL_MEMORY_BACKTRACE)
216 trace_cnt = backtrace( trace_buffer, MAX_BT );
217 cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
218 cur->trace_count = trace_cnt;
219#endif
220
221 if( ( heap.verify & MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
222 exit( 1 );
223
224 return ( (unsigned char *) cur ) + sizeof(memory_header);
225 }
226
227 p = ( (unsigned char *) cur ) + sizeof(memory_header) + len;
228 new = (memory_header *) p;
229
230 new->size = cur->size - len - sizeof(memory_header);
231 new->alloc = 0;
232 new->prev = cur;
233 new->next = cur->next;
234#if defined(POLARSSL_MEMORY_BACKTRACE)
235 new->trace = NULL;
236 new->trace_count = 0;
237#endif
238 new->magic1 = MAGIC1;
239 new->magic2 = MAGIC2;
240
241 if( new->next != NULL )
242 new->next->prev = new;
243
244 cur->alloc = 1;
245 cur->size = len;
246 cur->next = new;
247
248#if defined(POLARSSL_MEMORY_BACKTRACE)
249 trace_cnt = backtrace( trace_buffer, MAX_BT );
250 cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
251 cur->trace_count = trace_cnt;
252#endif
253
254 if( ( heap.verify & MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
255 exit( 1 );
256
257 return ( (unsigned char *) cur ) + sizeof(memory_header);
258}
259
260static void buffer_alloc_free( void *ptr )
261{
262 memory_header *hdr, *old;
263 unsigned char *p = (unsigned char *) ptr;
264
265
266 if( ptr == NULL || heap.buf == NULL || heap.first == NULL )
267 return;
268
269 if( p < heap.buf || p > heap.buf + heap.len )
270 {
271#if defined(POLARSSL_MEMORY_DEBUG)
272 fprintf(stderr, "FATAL: polarssl_free() outside of managed space\n");
273#endif
274 exit(1);
275 }
276
277 p -= sizeof(memory_header);
278 hdr = (memory_header *) p;
279
280 if( verify_header( hdr ) != 0 )
281 exit( 1 );
282
283 if( hdr->alloc != 1 )
284 {
285#if defined(POLARSSL_MEMORY_DEBUG)
286 fprintf(stderr, "FATAL: polarssl_free() on unallocated data\n");
287#endif
288 exit(1);
289 }
290
291 hdr->alloc = 0;
292
293 // Regroup with block before
294 //
295 if( hdr->prev != NULL && hdr->prev->alloc == 0 )
296 {
297 hdr->prev->size += sizeof(memory_header) + hdr->size;
298 hdr->prev->next = hdr->next;
299 old = hdr;
300 hdr = hdr->prev;
301
302 if( hdr->next != NULL )
303 hdr->next->prev = hdr;
304
305#if defined(POLARSSL_MEMORY_BACKTRACE)
306 free( old->trace );
307#endif
308 memset( old, 0, sizeof(memory_header) );
309 }
310
311 // Regroup with block after
312 //
313 if( hdr->next != NULL && hdr->next->alloc == 0 )
314 {
315 hdr->size += sizeof(memory_header) + hdr->next->size;
316 old = hdr->next;
317 hdr->next = hdr->next->next;
318
319 if( hdr->next != NULL )
320 hdr->next->prev = hdr;
321
322#if defined(POLARSSL_MEMORY_BACKTRACE)
323 free( old->trace );
324#endif
325 memset( old, 0, sizeof(memory_header) );
326 }
327
328#if defined(POLARSSL_MEMORY_BACKTRACE)
329 hdr->trace = NULL;
330 hdr->trace_count = 0;
331#endif
332
333 if( ( heap.verify & MEMORY_VERIFY_FREE ) && verify_chain() != 0 )
334 exit( 1 );
335}
336
337int memory_buffer_alloc_verify()
338{
339 return verify_chain();
340}
341
342#if defined(POLARSSL_MEMORY_DEBUG)
343void memory_buffer_alloc_status()
344{
345 if( heap.first->next == NULL )
346 fprintf(stderr, "All memory de-allocated in stack buffer\n");
347 else
348 {
349 fprintf(stderr, "Memory currently allocated:\n");
350 debug_chain();
351 }
352}
353#endif /* POLARSSL_MEMORY_BUFFER_ALLOC_DEBUG */
354
355int memory_buffer_alloc_init( unsigned char *buf, size_t len )
356{
357 polarssl_malloc = buffer_alloc_malloc;
358 polarssl_free = buffer_alloc_free;
359
360 memset( &heap, 0, sizeof(buffer_alloc_ctx) );
361 memset( buf, 0, len );
362
363 heap.buf = buf;
364 heap.len = len;
365
366 heap.first = (memory_header *) buf;
367 heap.first->size = len - sizeof(memory_header);
368 heap.first->magic1 = MAGIC1;
369 heap.first->magic2 = MAGIC2;
370
371 heap.largest_free = heap.first->size;
372
373 return( 0 );
374}
375
376#endif /* POLARSSL_MEMORY_C && POLARSSL_MEMORY_BUFFER_ALLOC_C */