added small memory debugger to detect memory leaks
[NeonServV5.git] / src / memoryDebug.c
1 /* memoryDebug.c - NeonServ v5.3
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #include "main.h"
18 #include "memoryDebug.h"
19 #include "memoryInfo.h"
20
21 #define FILE_NAME_LENGTH  256
22 #define OUTPUT_FILE "leak_info.txt"
23
24 #undef malloc
25 #undef calloc
26 #undef strdup
27 #undef free
28
29 struct MemoryNode {
30 void *address;
31 unsigned int size;
32 char file_name[FILE_NAME_LENGTH];
33 unsigned int line;
34 };
35
36 struct MemoryLeak {
37 struct MemoryNode mem_info;
38 struct MemoryLeak *next;
39 };
40
41 #ifdef HAVE_THREADS
42 static pthread_mutex_t synchronized;
43 #endif
44
45 static struct MemoryLeak *ptr_start = NULL;
46
47 static void add_mem_info(void * mem_ref, unsigned int size, const char *file, unsigned int line);
48 static void remove_mem_info(void * mem_ref);
49
50 void *xmalloc(unsigned int size, const char *file, unsigned int line) {
51     void *ptr = malloc(size);
52     if (ptr != NULL) {
53         add_mem_info(ptr, size, file, line);
54     }
55     return ptr;
56 }
57
58 void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line) {
59     void *ptr = calloc(elements, size);
60     if(ptr != NULL) {
61         add_mem_info(ptr, (elements * size), file, line);
62     }
63     return ptr;
64 }
65
66 char *xstrdup(const char *data, const char *file, unsigned int line) {
67     int len = strlen(data)+1;
68     char *ptr = malloc(len);
69     if(ptr != NULL) {
70         strcpy(ptr, data);
71         add_mem_info(ptr, len, file, line);
72     }
73     return ptr;
74 }
75
76 void xfree(void *mem_ref) {
77     remove_mem_info(mem_ref);
78     free(mem_ref);
79 }
80
81
82 static void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line) {
83     SYNCHRONIZE(synchronized);
84     struct MemoryLeak *mem_leak_info = malloc (sizeof(*mem_leak_info));
85     mem_leak_info->mem_info.address = mem_ref;
86     mem_leak_info->mem_info.size = size;
87     strcpy(mem_leak_info->mem_info.file_name, file);    
88     mem_leak_info->mem_info.line = line;
89     mem_leak_info->next = ptr_start;
90     ptr_start = mem_leak_info;
91     DESYNCHRONIZE(synchronized);
92 }
93
94 static void remove_mem_info(void *mem_ref) {
95     SYNCHRONIZE(synchronized);
96     struct MemoryLeak *leak_info, *next, *prev = NULL;
97     for(leak_info = ptr_start; leak_info; leak_info = next) {
98         next = leak_info->next;
99         if (leak_info->mem_info.address == mem_ref) {
100             if(prev)
101                 prev->next = next;
102             else
103                 ptr_start = next;
104             free(leak_info);
105             break;
106         } else 
107             prev = leak_info;
108     }
109     DESYNCHRONIZE(synchronized);
110 }
111
112 void report_mem_leak() {
113     SYNCHRONIZE(synchronized);
114     struct MemoryLeak *leak_info;
115     FILE *fp_write = fopen(OUTPUT_FILE, "wt");
116     char info[1024];
117
118     if(fp_write != NULL) {
119         sprintf(info, "%s\n", "Memory Leak Summary");
120         fwrite(info, (strlen(info)) , 1, fp_write);
121         sprintf(info, "%s\n", "-----------------------------------");    
122         fwrite(info, (strlen(info)) , 1, fp_write);
123         
124         for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
125             sprintf(info, "address : %p\n", leak_info->mem_info.address);
126             fwrite(info, (strlen(info)) , 1, fp_write);
127             sprintf(info, "size    : %d bytes\n", leak_info->mem_info.size);            
128             fwrite(info, (strlen(info)) , 1, fp_write);
129             sprintf(info, "file    : %s\n", leak_info->mem_info.file_name);
130             fwrite(info, (strlen(info)) , 1, fp_write);
131             sprintf(info, "line    : %d\n", leak_info->mem_info.line);
132             fwrite(info, (strlen(info)) , 1, fp_write);
133             sprintf(info, "%s\n", "-----------------------------------");    
134             fwrite(info, (strlen(info)) , 1, fp_write);
135         }
136     }
137     fclose(fp_write);
138     DESYNCHRONIZE(synchronized);
139 }
140
141 void initMemoryDebug() {
142     THREAD_MUTEX_INIT(synchronized);
143 }
144
145 struct memoryInfoFiles *getMemoryInfoFiles() {
146     SYNCHRONIZE(synchronized);
147     struct MemoryLeak *leak_info;
148     struct memoryInfoFiles *list = NULL, *element;
149     for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
150         for(element = list; element; element = element->next) {
151             if(!strcmp(leak_info->mem_info.file_name, element->filename)) {
152                 break;
153             }
154         }
155         if(!element) {
156             element = malloc(sizeof(*element));
157             element->filename = strdup(leak_info->mem_info.file_name);
158             element->allocations = 0;
159             element->allocated = 0;
160             element->next = list;
161             list = element;
162         }
163         element->allocations += 1;
164         element->allocated += leak_info->mem_info.size;
165     }
166     DESYNCHRONIZE(synchronized);
167     return element;
168 }
169
170 void freeMemoryInfoFiles(struct memoryInfoFiles *files) {
171     struct memoryInfoFiles *next;
172     for(;files;files = next) {
173         next = files->next;
174         free(files->filename);
175         free(files);
176     }
177 }
178
179 struct memoryInfoLines *getMemoryInfoLines(const char *filename) {
180     SYNCHRONIZE(synchronized);
181     struct MemoryLeak *leak_info;
182     struct memoryInfoLines *list = NULL, *element;
183     for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
184         if(stricmp(leak_info->mem_info.file_name, filename)) continue;
185         for(element = list; element; element = element->next) {
186             if(element->line == leak_info->mem_info.line && element->allocate == leak_info->mem_info.size) {
187                 break;
188             }
189         }
190         if(!element) {
191             element = malloc(sizeof(*element));
192             element->line = leak_info->mem_info.line;
193             element->allocations = 0;
194             element->allocate = leak_info->mem_info.size;
195             element->next = list;
196             list = element;
197         }
198         element->allocations++;
199     }
200     DESYNCHRONIZE(synchronized);
201     return element;
202 }
203
204 void freeMemoryInfoLines(struct memoryInfoLines *lines) {
205     struct memoryInfoLines *next;
206     for(;lines;lines = next) {
207         next = lines->next;
208         free(lines);
209     }
210 }