- implemented sa_config
[strongswan.git] / Source / charon / utils / allocator.c
1 /**
2 * @file allocator.c
3 *
4 * @brief Implementation of allocator_t.
5 */
6
7 /*
8 * Copyright (C) 2005 Jan Hutter, Martin Willi
9 * Hochschule fuer Technik Rapperswil
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 */
21
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <pthread.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <stdio.h>
28
29 #include "allocator.h"
30
31 #ifdef LEAK_DETECTIVE
32
33
34 typedef union memory_hdr_t memory_hdr_t;
35
36 /**
37 * Header of each allocated memory area.
38 *
39 * Ideas stolen from pluto's defs.c.
40 *
41 * Used to detect memory leaks.
42 */
43 union memory_hdr_t {
44 /**
45 * Informations
46 */
47 struct {
48 /**
49 * Filename withing memory was allocated
50 */
51 const char *filename;
52 /**
53 * Line number in given file
54 */
55 size_t line;
56 /**
57 * Allocated memory size. Needed for reallocation
58 */
59 size_t size_of_memory;
60 /**
61 * Link to the previous and next memory area
62 */
63 memory_hdr_t *older, *newer;
64 } info;
65 /**
66 * force maximal alignment ?
67 */
68 unsigned long junk;
69 };
70
71 typedef struct private_allocator_t private_allocator_t;
72
73 /**
74 * @brief Private allocator_t object.
75 *
76 * Contains private variables of allocator_t object.
77 */
78 struct private_allocator_t
79 {
80 /**
81 * Public part of an allocator_t object.
82 */
83 allocator_t public;
84
85 /**
86 * Global list of allocations.
87 *
88 * Thread-save through mutex.
89 */
90 memory_hdr_t *allocations;
91
92 /**
93 * Mutex used to make sure, all functions are thread-save.
94 */
95 pthread_mutex_t mutex;
96
97 /**
98 * Allocates memory with LEAK_DETECTION and
99 * returns an empty data area filled with zeros.
100 *
101 * @param this private_allocator_t object
102 * @param bytes number of bytes to allocate
103 * @param file filename from which the memory is allocated
104 * @param line line number in specific file
105 * @param use_mutex if FALSE no mutex is used for allocation
106 * @return
107 * - pointer to allocated memory area
108 * - NULL if out of ressources
109 */
110 void * (*allocate_special) (private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex);
111 };
112
113 /**
114 * Implementation of private_allocator_t.allocate_special.
115 */
116 static void *allocate_special(private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex)
117 {
118 memory_hdr_t *allocated_memory = malloc(sizeof(memory_hdr_t) + bytes);;
119
120 if (allocated_memory == NULL)
121 {
122 /* TODO LOG this case */
123 exit(-1);
124 }
125
126 if (use_mutex)
127 {
128 pthread_mutex_lock( &(this->mutex));
129 }
130
131 allocated_memory->info.line = line;
132 allocated_memory->info.filename = file;
133 allocated_memory->info.size_of_memory = bytes;
134 allocated_memory->info.older = this->allocations;
135 if (this->allocations != NULL)
136 {
137 this->allocations->info.newer = allocated_memory;
138 }
139 this->allocations = allocated_memory;
140 allocated_memory->info.newer = NULL;
141
142 /* fill memory with zero's */
143 memset(allocated_memory+1, '\0', bytes);
144 if (use_mutex)
145 {
146 pthread_mutex_unlock(&(this->mutex));
147 }
148
149 /* real memory starts after header */
150 return (allocated_memory+1);
151 }
152
153 /**
154 * Implementation of allocator_t.allocate.
155 */
156 static void * allocate(allocator_t *allocator,size_t bytes, char * file,int line)
157 {
158 private_allocator_t *this = (private_allocator_t *) allocator;
159 return (this->allocate_special(this,bytes, file,line,TRUE));
160 }
161
162 /**
163 * Implementation of allocator_t.allocate_as_chunk.
164 */
165 static chunk_t allocate_as_chunk(allocator_t *allocator,size_t bytes, char * file,int line)
166 {
167 private_allocator_t *this = (private_allocator_t *) allocator;
168 chunk_t new_chunk;
169 new_chunk.ptr = this->allocate_special(this,bytes, file,line,TRUE);
170 new_chunk.len = (new_chunk.ptr == NULL) ? 0 : bytes;
171 return new_chunk;
172 }
173
174 /**
175 * Implementation of allocator_t.free_pointer.
176 */
177 static void free_pointer(allocator_t *allocator, void * pointer)
178 {
179 private_allocator_t *this = (private_allocator_t *) allocator;
180 memory_hdr_t *allocated_memory;
181
182 if (pointer == NULL)
183 {
184 return;
185 }
186 pthread_mutex_lock( &(this->mutex));
187 allocated_memory = ((memory_hdr_t *)pointer) - 1;
188
189 if (allocated_memory->info.older != NULL)
190 {
191 assert(allocated_memory->info.older->info.newer == allocated_memory);
192 allocated_memory->info.older->info.newer = allocated_memory->info.newer;
193 }
194 if (allocated_memory->info.newer == NULL)
195 {
196 assert(allocated_memory == this->allocations);
197 this->allocations = allocated_memory->info.older;
198 }
199 else
200 {
201 assert(allocated_memory->info.newer->info.older == allocated_memory);
202 allocated_memory->info.newer->info.older = allocated_memory->info.older;
203 }
204 pthread_mutex_unlock(&(this->mutex));
205 free(allocated_memory);
206 }
207
208 /**
209 * Implementation of allocator_t.reallocate.
210 */
211 static void * reallocate(allocator_t *allocator, void * old, size_t bytes, char * file,int line)
212 {
213 private_allocator_t *this = (private_allocator_t *) allocator;
214 memory_hdr_t *allocated_memory;
215
216 if (old == NULL)
217 {
218 return NULL;
219 }
220
221 pthread_mutex_lock( &(this->mutex));
222 allocated_memory = ((memory_hdr_t *)old) - 1;
223
224 void *new_space = this->allocate_special(this,bytes,file,line,FALSE);
225
226 if (new_space == NULL)
227 {
228 pthread_mutex_unlock(&(this->mutex));
229 this->public.free_pointer(&(this->public),old);
230 return NULL;
231 }
232
233
234 /* the smaller size is copied to avoid overflows */
235 memcpy(new_space,old,(allocated_memory->info.size_of_memory < bytes) ? allocated_memory->info.size_of_memory : bytes);
236 pthread_mutex_unlock(&(this->mutex));
237 this->public.free_pointer(&(this->public),old);
238
239 return new_space;
240 }
241
242 /**
243 * Implementation of allocator_t.clone_bytes.
244 */
245 static void * clone_bytes(allocator_t *allocator,void * to_clone, size_t bytes, char * file, int line)
246 {
247 private_allocator_t *this = (private_allocator_t *) allocator;
248
249 if (to_clone == NULL)
250 {
251 return NULL;
252 }
253
254
255 void *new_space = this->allocate_special(this,bytes,file,line,TRUE);
256
257 if (new_space == NULL)
258 {
259 return NULL;
260 }
261
262 memcpy(new_space,to_clone,bytes);
263
264 return new_space;
265 }
266
267
268 /**
269 * Implementation of allocator_t.clone_chunk.
270 */
271 static chunk_t clone_chunk(allocator_t *allocator, chunk_t chunk, char * file, int line)
272 {
273 private_allocator_t *this = (private_allocator_t *) allocator;
274 chunk_t clone = CHUNK_INITIALIZER;
275
276 if (chunk.ptr && chunk.len > 0)
277 {
278 clone.ptr = this->allocate_special(this,chunk.len,file,line,TRUE);
279 clone.len = chunk.len;
280 memcpy(clone.ptr, chunk.ptr, chunk.len);
281 }
282
283 return clone;
284 }
285
286 /**
287 * Implementation of allocator_t.allocator_report_memory_leaks.
288 */
289 static void allocator_report_memory_leaks(allocator_t *allocator)
290 {
291 private_allocator_t *this = (private_allocator_t *) allocator;
292 memory_hdr_t *p = this->allocations;
293 memory_hdr_t *pprev = NULL;
294 unsigned long n = 0;
295
296 pthread_mutex_lock(&(this->mutex));
297
298 while (p != NULL)
299 {
300 assert(pprev == p->info.newer);
301 pprev = p;
302 p = p->info.older;
303 n++;
304 if (p == NULL || pprev->info.filename != p->info.filename)
305 {
306 if (n != 1)
307 fprintf(stderr,"LEAK: \"%lu * File %s, Line %d\"\n", n, pprev->info.filename,pprev->info.line);
308 else
309 fprintf(stderr,"LEAK: \"%s, Line %d\"\n", pprev->info.filename,pprev->info.line);
310 n = 0;
311 }
312 }
313 pthread_mutex_unlock( &(this->mutex));
314 }
315
316 /**
317 * Only Initiation of allocator object.
318 *
319 * All allocation macros use this object.
320 */
321 static private_allocator_t allocator = {
322 public: {allocate: allocate,
323 allocate_as_chunk: allocate_as_chunk,
324 free_pointer: free_pointer,
325 reallocate: reallocate,
326 clone_bytes : clone_bytes,
327 clone_chunk : clone_chunk,
328 report_memory_leaks: allocator_report_memory_leaks},
329 allocations: NULL,
330 allocate_special : allocate_special,
331 mutex: PTHREAD_MUTEX_INITIALIZER
332 };
333
334 allocator_t *global_allocator = &(allocator.public);
335 #else /* !LEAK_DETECTION */
336
337
338 /*
339 * Described in header
340 */
341 chunk_t allocator_alloc_as_chunk(size_t bytes)
342 {
343 chunk_t new_chunk;
344 new_chunk.ptr = malloc(bytes);
345 if ((new_chunk.ptr == NULL)
346 {
347 /* TODO log this case */
348 exit(-1);
349 }
350 new_chunk.len = bytes;
351 return new_chunk;
352
353 }
354
355 /*
356 * Described in header
357 */
358 void * allocator_realloc(void * old, size_t newsize)
359 {
360 void *data = realloc(old,newsize);
361 return data;
362 }
363
364 /*
365 * Described in header
366 */
367 void * allocator_clone_bytes(void * pointer, size_t size)
368 {
369
370 void *data;
371 data = malloc(size);
372
373 if (data == NULL){exit(-1);}
374 memmove(data,pointer,size);
375
376 return (data);
377 }
378
379
380 /**
381 * Described in header
382 */
383 static chunk_t clone_chunk(chunk_t chunk)
384 {
385 chunk_t clone = CHUNK_INITIALIZER;
386
387 if (chunk.ptr && chunk.len > 0)
388 {
389 clone.ptr = malloc(chunk.len);
390 if (clone.ptr == NULL) {exit(-1)};
391 clone.len = chunk.len;
392 memcpy(clone.ptr, chunk.ptr, chunk.len);
393 }
394
395 return clone;
396 }
397
398 /*
399 * Described in header
400 */
401 void allocator_free_chunk(chunk_t *chunk)
402 {
403 free(chunk->ptr);
404 chunk->ptr = NULL;
405 chunk->len = 0;
406 }
407
408
409 #endif /* LEAK_DETECTION */