diff options
Diffstat (limited to 'Source/charon/utils/allocator.c')
-rw-r--r-- | Source/charon/utils/allocator.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/Source/charon/utils/allocator.c b/Source/charon/utils/allocator.c new file mode 100644 index 000000000..290b1de3b --- /dev/null +++ b/Source/charon/utils/allocator.c @@ -0,0 +1,347 @@ +/** + * @file allocator.c + * + * @brief Memory allocation with LEAK_DETECTION support + * + * Thread-save implementation + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <pthread.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> + +#include "allocator.h" + +#ifdef LEAK_DETECTIVE + +/** + * Header of each allocated memory area + * + * Used to detect memory leaks + */ +typedef union memory_hdr_u memory_hdr_t; + +union memory_hdr_u { + struct { + /** + * Filename withing memory was allocated + */ + const char *filename; + /** + * Line number in given file + */ + size_t line; + /** + * Allocated memory size. Needed for reallocation + */ + size_t size_of_memory; + /** + * Link to the previous and next memory area + */ + memory_hdr_t *older, *newer; + } info; /* info */ + /** + * force maximal alignment ? + */ + unsigned long junk; +}; + +/** + * @brief Private allocator_t object. + * + * Contains private variables of allocator_t object. + */ +typedef struct private_allocator_s private_allocator_t; + +struct private_allocator_s +{ + /** + * Public part of an allocator_t object. + */ + allocator_t public; + + /** + * Global list of allocations + * + * Thread-save through mutex + */ + memory_hdr_t *allocations; + + /** + * Mutex used to make sure, all functions are thread-save + */ + pthread_mutex_t mutex; + + /** + * Allocates memory with LEAK_DETECTION and + * returns an empty data area filled with zeros. + * + * @param this private_allocator_t object + * @param bytes number of bytes to allocate + * @param file filename from which the memory is allocated + * @param line line number in specific file + * @param use_mutex If FALSE no mutex is used for allocation + * @return + * - pointer to allocated memory area if successful + * - NULL otherwise + */ + void * (*allocate_special) (private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex); +}; + +/** + * Implements private_allocator_t's function allocate_special. + * See #private_allocator_s.allocate_special for description. + */ +static void *allocate_special(private_allocator_t *this,size_t bytes, char * file,int line, bool use_mutex) +{ + memory_hdr_t *allocated_memory = malloc(sizeof(memory_hdr_t) + bytes); + + if (allocated_memory == NULL) + { + return allocated_memory; + } + + if (use_mutex) + { + pthread_mutex_lock( &(this->mutex)); + } + + allocated_memory->info.line = line; + allocated_memory->info.filename = file; + allocated_memory->info.size_of_memory = bytes; + allocated_memory->info.older = this->allocations; + if (this->allocations != NULL) + { + this->allocations->info.newer = allocated_memory; + } + this->allocations = allocated_memory; + allocated_memory->info.newer = NULL; + + /* fill memory with zero's */ + memset(allocated_memory+1, '\0', bytes); + if (use_mutex) + { + pthread_mutex_unlock(&(this->mutex)); + } + + /* real memory starts after header */ + return (allocated_memory+1); +} + +/** + * Implements allocator_t's function allocate. + * See #allocator_s.allocate for description. + */ +static void * allocate(allocator_t *allocator,size_t bytes, char * file,int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + return (this->allocate_special(this,bytes, file,line,TRUE)); +} + +/** + * Implements allocator_t's function allocate_as_chunk. + * See #allocator_s.allocate_as_chunk for description. + */ +static chunk_t allocate_as_chunk(allocator_t *allocator,size_t bytes, char * file,int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + chunk_t new_chunk; + new_chunk.ptr = this->allocate_special(this,bytes, file,line,TRUE); + new_chunk.len = (new_chunk.ptr == NULL) ? 0 : bytes; + return new_chunk; +} + +/* + * Implements allocator_t's free_pointer function. + * See #allocator_s.free_pointer for description. + */ +static void free_pointer(allocator_t *allocator, void * pointer) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + memory_hdr_t *allocated_memory; + + if (pointer == NULL) + { + return; + } + pthread_mutex_lock( &(this->mutex)); + allocated_memory = ((memory_hdr_t *)pointer) - 1; + + if (allocated_memory->info.older != NULL) + { + assert(allocated_memory->info.older->info.newer == allocated_memory); + allocated_memory->info.older->info.newer = allocated_memory->info.newer; + } + if (allocated_memory->info.newer == NULL) + { + assert(allocated_memory == this->allocations); + this->allocations = allocated_memory->info.older; + } + else + { + assert(allocated_memory->info.newer->info.older == allocated_memory); + allocated_memory->info.newer->info.older = allocated_memory->info.older; + } + pthread_mutex_unlock(&(this->mutex)); + free(allocated_memory); +} + +/* + * Implements allocator_t's reallocate function. + * See #allocator_s.reallocate for description. + */ +static void * reallocate(allocator_t *allocator, void * old, size_t bytes, char * file,int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + memory_hdr_t *allocated_memory; + + if (old == NULL) + { + return NULL; + } + + pthread_mutex_lock( &(this->mutex)); + allocated_memory = ((memory_hdr_t *)old) - 1; + + void *new_space = this->allocate_special(this,bytes,file,line,FALSE); + + if (new_space == NULL) + { + pthread_mutex_unlock(&(this->mutex)); + this->public.free_pointer(&(this->public),old); + return NULL; + } + + + /* the smaller size is copied to avoid overflows */ + memcpy(new_space,old,(allocated_memory->info.size_of_memory < bytes) ? allocated_memory->info.size_of_memory : bytes); + pthread_mutex_unlock(&(this->mutex)); + this->public.free_pointer(&(this->public),old); + + return new_space; +} + +/* + * Implements allocator_t's clone_bytes function. + * See #allocator_s.clone_bytes for description. + */ +static void * clone_bytes(allocator_t *allocator,void * to_clone, size_t bytes, char * file, int line) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + + if (to_clone == NULL) + { + return NULL; + } + + + void *new_space = this->allocate_special(this,bytes,file,line,TRUE); + + if (new_space == NULL) + { + return NULL; + } + + memcpy(new_space,to_clone,bytes); + + return new_space; +} + +/* + * Implements allocator_t's report_memory_leaks allocate. + * See #allocator_s.report_memory_leaks for description. + */ +static void allocator_report_memory_leaks(allocator_t *allocator) +{ + private_allocator_t *this = (private_allocator_t *) allocator; + memory_hdr_t *p = this->allocations; + memory_hdr_t *pprev = NULL; + unsigned long n = 0; + + pthread_mutex_lock(&(this->mutex)); + + while (p != NULL) + { + assert(pprev == p->info.newer); + pprev = p; + p = p->info.older; + n++; + if (p == NULL || pprev->info.filename != p->info.filename) + { + if (n != 1) + fprintf(stderr,"LEAK: \"%lu * File %s, Line %d\"\n", n, pprev->info.filename,pprev->info.line); + else + fprintf(stderr,"LEAK: \"%s, Line %d\"\n", pprev->info.filename,pprev->info.line); + n = 0; + } + } + pthread_mutex_unlock( &(this->mutex)); +} + +/** + * Only initiation of allocator object. + * + * All allocation macros use this object. + */ +static private_allocator_t allocator = { + public: {allocate: allocate, + allocate_as_chunk: allocate_as_chunk, + free_pointer: free_pointer, + reallocate: reallocate, + clone_bytes : clone_bytes, + report_memory_leaks: allocator_report_memory_leaks}, + allocations: NULL, + allocate_special : allocate_special, + mutex: PTHREAD_MUTEX_INITIALIZER +}; + +allocator_t *global_allocator = &(allocator.public); +#else /* !LEAK_DETECTION */ + + +chunk_t allocator_alloc_as_chunk(size_t bytes) +{ + chunk_t new_chunk; + new_chunk.ptr = malloc(bytes); + new_chunk.len = (new_chunk.ptr == NULL) ? 0 : bytes; + return new_chunk; + +} + +void * allocator_clone_bytes(void * pointer, size_t size) +{ + void *data; + data = malloc(size); + if (data == NULL){ return NULL;} + memcpy(data,pointer,size); + return (data); +} + + +void allocator_free_chunk(chunk_t chunk) +{ + free(chunk.ptr); +} + + +#endif /* LEAK_DETECTION */ + + |