46194e85f2896b24ab7ee6cddd0bc4427488f72e
[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 * Implementation of allocator_t.allocator_report_memory_leaks.
269 */
270 static void allocator_report_memory_leaks(allocator_t *allocator)
271 {
272 private_allocator_t *this = (private_allocator_t *) allocator;
273 memory_hdr_t *p = this->allocations;
274 memory_hdr_t *pprev = NULL;
275 unsigned long n = 0;
276
277 pthread_mutex_lock(&(this->mutex));
278
279 while (p != NULL)
280 {
281 assert(pprev == p->info.newer);
282 pprev = p;
283 p = p->info.older;
284 n++;
285 if (p == NULL || pprev->info.filename != p->info.filename)
286 {
287 if (n != 1)
288 fprintf(stderr,"LEAK: \"%lu * File %s, Line %d\"\n", n, pprev->info.filename,pprev->info.line);
289 else
290 fprintf(stderr,"LEAK: \"%s, Line %d\"\n", pprev->info.filename,pprev->info.line);
291 n = 0;
292 }
293 }
294 pthread_mutex_unlock( &(this->mutex));
295 }
296
297 /**
298 * Only Initiation of allocator object.
299 *
300 * All allocation macros use this object.
301 */
302 static private_allocator_t allocator = {
303 public: {allocate: allocate,
304 allocate_as_chunk: allocate_as_chunk,
305 free_pointer: free_pointer,
306 reallocate: reallocate,
307 clone_bytes : clone_bytes,
308 report_memory_leaks: allocator_report_memory_leaks},
309 allocations: NULL,
310 allocate_special : allocate_special,
311 mutex: PTHREAD_MUTEX_INITIALIZER
312 };
313
314 allocator_t *global_allocator = &(allocator.public);
315 #else /* !LEAK_DETECTION */
316
317
318 /*
319 * Described in header
320 */
321 chunk_t allocator_alloc_as_chunk(size_t bytes)
322 {
323 chunk_t new_chunk;
324 new_chunk.ptr = malloc(bytes);
325 if ((new_chunk.ptr == NULL)
326 {
327 /* TODO log this case */
328 exit(-1);
329 }
330 new_chunk.len = bytes;
331 return new_chunk;
332
333 }
334
335 /*
336 * Described in header
337 */
338 void * allocator_realloc(void * old, size_t newsize)
339 {
340 void *data = realloc(old,newsize);
341 return data;
342 }
343
344 /*
345 * Described in header
346 */
347 void * allocator_clone_bytes(void * pointer, size_t size)
348 {
349
350 void *data;
351 data = malloc(size);
352
353 if (data == NULL){exit(-1);}
354 memmove(data,pointer,size);
355
356 return (data);
357 }
358
359 /*
360 * Described in header
361 */
362 void allocator_free_chunk(chunk_t *chunk)
363 {
364 free(chunk->ptr);
365 chunk->ptr = NULL;
366 chunk->len = 0;
367 }
368
369
370 #endif /* LEAK_DETECTION */