blob: e9068ae028de7984ab066f77ea404db2c066859c [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;
Paul Bakker891998e2013-07-03 14:45:05 +020068#if defined(POLARSSL_MEMORY_DEBUG)
69 size_t malloc_count;
70 size_t free_count;
71 size_t total_used;
72 size_t maximum_used;
73 size_t header_count;
74#endif
Paul Bakker6e339b52013-07-03 13:37:05 +020075}
76buffer_alloc_ctx;
77
78static buffer_alloc_ctx heap;
79
80#if defined(POLARSSL_MEMORY_DEBUG)
81static void debug_header( memory_header *hdr )
82{
83#if defined(POLARSSL_MEMORY_BACKTRACE)
84 size_t i;
85#endif
86
87 fprintf(stderr, "HDR: PTR(%10u), PREV(%10u), NEXT(%10u), ALLOC(%u), SIZE(%10u)\n",
88 (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next,
89 hdr->alloc, hdr->size );
90
91#if defined(POLARSSL_MEMORY_BACKTRACE)
92 fprintf(stderr, "TRACE: \n");
93 for( i = 0; i < hdr->trace_count; i++ )
94 fprintf(stderr, "%s\n", hdr->trace[i]);
95#endif
96}
97
98static void debug_chain()
99{
100 memory_header *cur = heap.first;
101
102 while( cur != NULL )
103 {
104 debug_header( cur );
105 fprintf(stderr, "\n");
106 cur = cur->next;
107 }
108}
109#endif /* POLARSSL_MEMORY_DEBUG */
110
111static int verify_header( memory_header *hdr )
112{
113 if( hdr->magic1 != MAGIC1 )
114 {
115#if defined(POLARSSL_MEMORY_DEBUG)
116 fprintf(stderr, "FATAL: MAGIC1 mismatch\n");
117#endif
118 return( 1 );
119 }
120
121 if( hdr->magic2 != MAGIC2 )
122 {
123#if defined(POLARSSL_MEMORY_DEBUG)
124 fprintf(stderr, "FATAL: MAGIC2 mismatch\n");
125#endif
126 return( 1 );
127 }
128
129 if( hdr->alloc > 1 )
130 {
131#if defined(POLARSSL_MEMORY_DEBUG)
132 fprintf(stderr, "FATAL: alloc has illegal value\n");
133#endif
134 return( 1 );
135 }
136
137 return( 0 );
138}
139
140static int verify_chain()
141{
142 memory_header *prv = heap.first, *cur = heap.first->next;
143
144 if( verify_header( heap.first ) != 0 )
145 {
146#if defined(POLARSSL_MEMORY_DEBUG)
147 fprintf(stderr, "FATAL: verification of first header failed\n");
148#endif
149 return( 1 );
150 }
151
152 if( heap.first->prev != NULL )
153 {
154#if defined(POLARSSL_MEMORY_DEBUG)
155 fprintf(stderr, "FATAL: verification failed: first->prev != NULL\n");
156#endif
157 return( 1 );
158 }
159
160 while( cur != NULL )
161 {
162 if( verify_header( cur ) != 0 )
163 {
164#if defined(POLARSSL_MEMORY_DEBUG)
165 fprintf(stderr, "FATAL: verification of header failed\n");
166#endif
167 return( 1 );
168 }
169
170 if( cur->prev != prv )
171 {
172#if defined(POLARSSL_MEMORY_DEBUG)
173 fprintf(stderr, "FATAL: verification failed: cur->prev != prv\n");
174#endif
175 return( 1 );
176 }
177
178 prv = cur;
179 cur = cur->next;
180 }
181
182 return( 0 );
183}
184
185static void *buffer_alloc_malloc( size_t len )
186{
187 memory_header *new, *cur = heap.first;
188 unsigned char *p;
189#if defined(POLARSSL_MEMORY_BACKTRACE)
190 void *trace_buffer[MAX_BT];
191 size_t trace_cnt;
192#endif
193
194 if( heap.buf == NULL || heap.first == NULL )
195 return( NULL );
196
197 if( len % POLARSSL_MEMORY_ALIGN_MULTIPLE )
198 {
199 len -= len % POLARSSL_MEMORY_ALIGN_MULTIPLE;
200 len += POLARSSL_MEMORY_ALIGN_MULTIPLE;
201 }
202
203 // Find block that fits
204 //
205 while( cur != NULL )
206 {
207 if( cur->alloc == 0 && cur->size >= len )
208 break;
209
210 cur = cur->next;
211 }
212
213 if( cur == NULL )
214 return( NULL );
215
Paul Bakker891998e2013-07-03 14:45:05 +0200216#if defined(POLARSSL_MEMORY_DEBUG)
217 heap.malloc_count++;
218#endif
219
Paul Bakker6e339b52013-07-03 13:37:05 +0200220 // Found location, split block if > memory_header + 4 room left
221 //
222 if( cur->size - len < sizeof(memory_header) + POLARSSL_MEMORY_ALIGN_MULTIPLE )
223 {
224 cur->alloc = 1;
225
Paul Bakker891998e2013-07-03 14:45:05 +0200226#if defined(POLARSSL_MEMORY_DEBUG)
227 heap.total_used += cur->size;
228 if( heap.total_used > heap.maximum_used)
229 heap.maximum_used = heap.total_used;
230#endif
Paul Bakker6e339b52013-07-03 13:37:05 +0200231#if defined(POLARSSL_MEMORY_BACKTRACE)
232 trace_cnt = backtrace( trace_buffer, MAX_BT );
233 cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
234 cur->trace_count = trace_cnt;
235#endif
236
237 if( ( heap.verify & MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
238 exit( 1 );
239
240 return ( (unsigned char *) cur ) + sizeof(memory_header);
241 }
242
243 p = ( (unsigned char *) cur ) + sizeof(memory_header) + len;
244 new = (memory_header *) p;
245
246 new->size = cur->size - len - sizeof(memory_header);
247 new->alloc = 0;
248 new->prev = cur;
249 new->next = cur->next;
250#if defined(POLARSSL_MEMORY_BACKTRACE)
251 new->trace = NULL;
252 new->trace_count = 0;
253#endif
254 new->magic1 = MAGIC1;
255 new->magic2 = MAGIC2;
256
257 if( new->next != NULL )
258 new->next->prev = new;
259
260 cur->alloc = 1;
261 cur->size = len;
262 cur->next = new;
263
Paul Bakker891998e2013-07-03 14:45:05 +0200264#if defined(POLARSSL_MEMORY_DEBUG)
265 heap.header_count++;
266 heap.total_used += cur->size;
267 if( heap.total_used > heap.maximum_used)
268 heap.maximum_used = heap.total_used;
269#endif
Paul Bakker6e339b52013-07-03 13:37:05 +0200270#if defined(POLARSSL_MEMORY_BACKTRACE)
271 trace_cnt = backtrace( trace_buffer, MAX_BT );
272 cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
273 cur->trace_count = trace_cnt;
274#endif
275
276 if( ( heap.verify & MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
277 exit( 1 );
278
279 return ( (unsigned char *) cur ) + sizeof(memory_header);
280}
281
282static void buffer_alloc_free( void *ptr )
283{
284 memory_header *hdr, *old;
285 unsigned char *p = (unsigned char *) ptr;
286
287
288 if( ptr == NULL || heap.buf == NULL || heap.first == NULL )
289 return;
290
291 if( p < heap.buf || p > heap.buf + heap.len )
292 {
293#if defined(POLARSSL_MEMORY_DEBUG)
294 fprintf(stderr, "FATAL: polarssl_free() outside of managed space\n");
295#endif
296 exit(1);
297 }
298
299 p -= sizeof(memory_header);
300 hdr = (memory_header *) p;
301
302 if( verify_header( hdr ) != 0 )
303 exit( 1 );
304
305 if( hdr->alloc != 1 )
306 {
307#if defined(POLARSSL_MEMORY_DEBUG)
308 fprintf(stderr, "FATAL: polarssl_free() on unallocated data\n");
309#endif
310 exit(1);
311 }
312
313 hdr->alloc = 0;
314
Paul Bakker891998e2013-07-03 14:45:05 +0200315#if defined(POLARSSL_MEMORY_DEBUG)
316 heap.free_count++;
317 heap.total_used -= hdr->size;
318#endif
319
Paul Bakker6e339b52013-07-03 13:37:05 +0200320 // Regroup with block before
321 //
322 if( hdr->prev != NULL && hdr->prev->alloc == 0 )
323 {
Paul Bakker891998e2013-07-03 14:45:05 +0200324#if defined(POLARSSL_MEMORY_DEBUG)
325 heap.header_count--;
326#endif
Paul Bakker6e339b52013-07-03 13:37:05 +0200327 hdr->prev->size += sizeof(memory_header) + hdr->size;
328 hdr->prev->next = hdr->next;
329 old = hdr;
330 hdr = hdr->prev;
331
332 if( hdr->next != NULL )
333 hdr->next->prev = hdr;
334
335#if defined(POLARSSL_MEMORY_BACKTRACE)
336 free( old->trace );
337#endif
338 memset( old, 0, sizeof(memory_header) );
339 }
340
341 // Regroup with block after
342 //
343 if( hdr->next != NULL && hdr->next->alloc == 0 )
344 {
Paul Bakker891998e2013-07-03 14:45:05 +0200345#if defined(POLARSSL_MEMORY_DEBUG)
346 heap.header_count--;
347#endif
Paul Bakker6e339b52013-07-03 13:37:05 +0200348 hdr->size += sizeof(memory_header) + hdr->next->size;
349 old = hdr->next;
350 hdr->next = hdr->next->next;
351
352 if( hdr->next != NULL )
353 hdr->next->prev = hdr;
354
355#if defined(POLARSSL_MEMORY_BACKTRACE)
356 free( old->trace );
357#endif
358 memset( old, 0, sizeof(memory_header) );
359 }
360
361#if defined(POLARSSL_MEMORY_BACKTRACE)
362 hdr->trace = NULL;
363 hdr->trace_count = 0;
364#endif
365
366 if( ( heap.verify & MEMORY_VERIFY_FREE ) && verify_chain() != 0 )
367 exit( 1 );
368}
369
370int memory_buffer_alloc_verify()
371{
372 return verify_chain();
373}
374
375#if defined(POLARSSL_MEMORY_DEBUG)
376void memory_buffer_alloc_status()
377{
Paul Bakker891998e2013-07-03 14:45:05 +0200378 fprintf(stderr, "Current use: %u blocks / %u bytes, max: %u bytes, malloc / free: %u / %u\n", heap.header_count, heap.total_used, heap.maximum_used, heap.malloc_count, heap.free_count);
379
Paul Bakker6e339b52013-07-03 13:37:05 +0200380 if( heap.first->next == NULL )
381 fprintf(stderr, "All memory de-allocated in stack buffer\n");
382 else
383 {
384 fprintf(stderr, "Memory currently allocated:\n");
385 debug_chain();
386 }
387}
388#endif /* POLARSSL_MEMORY_BUFFER_ALLOC_DEBUG */
389
390int memory_buffer_alloc_init( unsigned char *buf, size_t len )
391{
392 polarssl_malloc = buffer_alloc_malloc;
393 polarssl_free = buffer_alloc_free;
394
395 memset( &heap, 0, sizeof(buffer_alloc_ctx) );
396 memset( buf, 0, len );
397
398 heap.buf = buf;
399 heap.len = len;
400
401 heap.first = (memory_header *) buf;
402 heap.first->size = len - sizeof(memory_header);
403 heap.first->magic1 = MAGIC1;
404 heap.first->magic2 = MAGIC2;
405
406 heap.largest_free = heap.first->size;
407
408 return( 0 );
409}
410
411#endif /* POLARSSL_MEMORY_C && POLARSSL_MEMORY_BUFFER_ALLOC_C */