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