added small memory debugger to detect memory leaks
[NeonServV5.git] / src / memoryDebug.c
diff --git a/src/memoryDebug.c b/src/memoryDebug.c
new file mode 100644 (file)
index 0000000..442e618
--- /dev/null
@@ -0,0 +1,210 @@
+/* memoryDebug.c - NeonServ v5.3
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#include "main.h"
+#include "memoryDebug.h"
+#include "memoryInfo.h"
+
+#define FILE_NAME_LENGTH  256
+#define OUTPUT_FILE "leak_info.txt"
+
+#undef malloc
+#undef calloc
+#undef strdup
+#undef free
+
+struct MemoryNode {
+void *address;
+unsigned int size;
+char file_name[FILE_NAME_LENGTH];
+unsigned int line;
+};
+
+struct MemoryLeak {
+struct MemoryNode mem_info;
+struct MemoryLeak *next;
+};
+
+#ifdef HAVE_THREADS
+static pthread_mutex_t synchronized;
+#endif
+
+static struct MemoryLeak *ptr_start = NULL;
+
+static void add_mem_info(void * mem_ref, unsigned int size, const char *file, unsigned int line);
+static void remove_mem_info(void * mem_ref);
+
+void *xmalloc(unsigned int size, const char *file, unsigned int line) {
+    void *ptr = malloc(size);
+    if (ptr != NULL) {
+        add_mem_info(ptr, size, file, line);
+    }
+    return ptr;
+}
+
+void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line) {
+    void *ptr = calloc(elements, size);
+    if(ptr != NULL) {
+        add_mem_info(ptr, (elements * size), file, line);
+    }
+    return ptr;
+}
+
+char *xstrdup(const char *data, const char *file, unsigned int line) {
+    int len = strlen(data)+1;
+    char *ptr = malloc(len);
+    if(ptr != NULL) {
+        strcpy(ptr, data);
+        add_mem_info(ptr, len, file, line);
+    }
+    return ptr;
+}
+
+void xfree(void *mem_ref) {
+    remove_mem_info(mem_ref);
+    free(mem_ref);
+}
+
+
+static void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line) {
+    SYNCHRONIZE(synchronized);
+    struct MemoryLeak *mem_leak_info = malloc (sizeof(*mem_leak_info));
+    mem_leak_info->mem_info.address = mem_ref;
+    mem_leak_info->mem_info.size = size;
+    strcpy(mem_leak_info->mem_info.file_name, file);    
+    mem_leak_info->mem_info.line = line;
+    mem_leak_info->next = ptr_start;
+    ptr_start = mem_leak_info;
+    DESYNCHRONIZE(synchronized);
+}
+
+static void remove_mem_info(void *mem_ref) {
+    SYNCHRONIZE(synchronized);
+    struct MemoryLeak *leak_info, *next, *prev = NULL;
+    for(leak_info = ptr_start; leak_info; leak_info = next) {
+        next = leak_info->next;
+        if (leak_info->mem_info.address == mem_ref) {
+            if(prev)
+                prev->next = next;
+            else
+                ptr_start = next;
+            free(leak_info);
+            break;
+        } else 
+            prev = leak_info;
+    }
+    DESYNCHRONIZE(synchronized);
+}
+
+void report_mem_leak() {
+    SYNCHRONIZE(synchronized);
+    struct MemoryLeak *leak_info;
+    FILE *fp_write = fopen(OUTPUT_FILE, "wt");
+    char info[1024];
+
+    if(fp_write != NULL) {
+        sprintf(info, "%s\n", "Memory Leak Summary");
+        fwrite(info, (strlen(info)) , 1, fp_write);
+        sprintf(info, "%s\n", "-----------------------------------");    
+        fwrite(info, (strlen(info)) , 1, fp_write);
+        
+        for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
+            sprintf(info, "address : %p\n", leak_info->mem_info.address);
+            fwrite(info, (strlen(info)) , 1, fp_write);
+            sprintf(info, "size    : %d bytes\n", leak_info->mem_info.size);            
+            fwrite(info, (strlen(info)) , 1, fp_write);
+            sprintf(info, "file    : %s\n", leak_info->mem_info.file_name);
+            fwrite(info, (strlen(info)) , 1, fp_write);
+            sprintf(info, "line    : %d\n", leak_info->mem_info.line);
+            fwrite(info, (strlen(info)) , 1, fp_write);
+            sprintf(info, "%s\n", "-----------------------------------");    
+            fwrite(info, (strlen(info)) , 1, fp_write);
+        }
+    }
+    fclose(fp_write);
+    DESYNCHRONIZE(synchronized);
+}
+
+void initMemoryDebug() {
+    THREAD_MUTEX_INIT(synchronized);
+}
+
+struct memoryInfoFiles *getMemoryInfoFiles() {
+    SYNCHRONIZE(synchronized);
+    struct MemoryLeak *leak_info;
+    struct memoryInfoFiles *list = NULL, *element;
+    for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
+        for(element = list; element; element = element->next) {
+            if(!strcmp(leak_info->mem_info.file_name, element->filename)) {
+                break;
+            }
+        }
+        if(!element) {
+            element = malloc(sizeof(*element));
+            element->filename = strdup(leak_info->mem_info.file_name);
+            element->allocations = 0;
+            element->allocated = 0;
+            element->next = list;
+            list = element;
+        }
+        element->allocations += 1;
+        element->allocated += leak_info->mem_info.size;
+    }
+    DESYNCHRONIZE(synchronized);
+    return element;
+}
+
+void freeMemoryInfoFiles(struct memoryInfoFiles *files) {
+    struct memoryInfoFiles *next;
+    for(;files;files = next) {
+        next = files->next;
+        free(files->filename);
+        free(files);
+    }
+}
+
+struct memoryInfoLines *getMemoryInfoLines(const char *filename) {
+    SYNCHRONIZE(synchronized);
+    struct MemoryLeak *leak_info;
+    struct memoryInfoLines *list = NULL, *element;
+    for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
+        if(stricmp(leak_info->mem_info.file_name, filename)) continue;
+        for(element = list; element; element = element->next) {
+            if(element->line == leak_info->mem_info.line && element->allocate == leak_info->mem_info.size) {
+                break;
+            }
+        }
+        if(!element) {
+            element = malloc(sizeof(*element));
+            element->line = leak_info->mem_info.line;
+            element->allocations = 0;
+            element->allocate = leak_info->mem_info.size;
+            element->next = list;
+            list = element;
+        }
+        element->allocations++;
+    }
+    DESYNCHRONIZE(synchronized);
+    return element;
+}
+
+void freeMemoryInfoLines(struct memoryInfoLines *lines) {
+    struct memoryInfoLines *next;
+    for(;lines;lines = next) {
+        next = lines->next;
+        free(lines);
+    }
+}