e870f4ba4854f2253a1b424b41c7b71a91dc0f81
[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 unsigned int own_allocated_memleaks = 0;
48
49 static void add_mem_info(void * mem_ref, unsigned int size, const char *file, unsigned int line);
50 static void remove_mem_info(void * mem_ref);
51
52 void *xmalloc(unsigned int size, const char *file, unsigned int line) {
53     void *ptr = malloc(size);
54     if (ptr != NULL) {
55         add_mem_info(ptr, size, file, line);
56     }
57     return ptr;
58 }
59
60 void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line) {
61     void *ptr = calloc(elements, size);
62     if(ptr != NULL) {
63         add_mem_info(ptr, (elements * size), file, line);
64     }
65     return ptr;
66 }
67
68 char *xstrdup(const char *data, const char *file, unsigned int line) {
69     int len = strlen(data)+1;
70     char *ptr = malloc(len);
71     if(ptr != NULL) {
72         strcpy(ptr, data);
73         add_mem_info(ptr, len, file, line);
74     }
75     return ptr;
76 }
77
78 void xfree(void *mem_ref) {
79     remove_mem_info(mem_ref);
80     free(mem_ref);
81 }
82
83
84 static void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line) {
85     SYNCHRONIZE(synchronized);
86     struct MemoryLeak *mem_leak_info = malloc(sizeof(*mem_leak_info));
87     own_allocated_memleaks++;
88     mem_leak_info->mem_info.address = mem_ref;
89     mem_leak_info->mem_info.size = size;
90     strcpy(mem_leak_info->mem_info.file_name, file);    
91     mem_leak_info->mem_info.line = line;
92     mem_leak_info->next = ptr_start;
93     ptr_start = mem_leak_info;
94     DESYNCHRONIZE(synchronized);
95 }
96
97 static void remove_mem_info(void *mem_ref) {
98     SYNCHRONIZE(synchronized);
99     struct MemoryLeak *leak_info, *next, *prev = NULL;
100     for(leak_info = ptr_start; leak_info; leak_info = next) {
101         next = leak_info->next;
102         if (leak_info->mem_info.address == mem_ref) {
103             if(prev)
104                 prev->next = next;
105             else
106                 ptr_start = next;
107             own_allocated_memleaks--;
108             free(leak_info);
109             break;
110         } else 
111             prev = leak_info;
112     }
113     DESYNCHRONIZE(synchronized);
114 }
115
116 void report_mem_leak() {
117     SYNCHRONIZE(synchronized);
118     struct MemoryLeak *leak_info;
119     FILE *fp_write = fopen(OUTPUT_FILE, "wt");
120     char info[1024];
121
122     if(fp_write != NULL) {
123         sprintf(info, "%s\n", "Memory Leak Summary");
124         fwrite(info, (strlen(info)) , 1, fp_write);
125         sprintf(info, "%s\n", "-----------------------------------");    
126         fwrite(info, (strlen(info)) , 1, fp_write);
127         
128         for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
129             sprintf(info, "address : %p\n", leak_info->mem_info.address);
130             fwrite(info, (strlen(info)) , 1, fp_write);
131             sprintf(info, "size    : %d bytes\n", leak_info->mem_info.size);            
132             fwrite(info, (strlen(info)) , 1, fp_write);
133             sprintf(info, "file    : %s\n", leak_info->mem_info.file_name);
134             fwrite(info, (strlen(info)) , 1, fp_write);
135             sprintf(info, "line    : %d\n", leak_info->mem_info.line);
136             fwrite(info, (strlen(info)) , 1, fp_write);
137             sprintf(info, "%s\n", "-----------------------------------");    
138             fwrite(info, (strlen(info)) , 1, fp_write);
139         }
140     }
141     fclose(fp_write);
142     DESYNCHRONIZE(synchronized);
143 }
144
145 void initMemoryDebug() {
146     THREAD_MUTEX_INIT(synchronized);
147 }
148
149 struct memoryInfoFiles *getMemoryInfoFiles() {
150     SYNCHRONIZE(synchronized);
151     struct MemoryLeak *leak_info;
152     struct memoryInfoFiles *list = NULL, *element;
153     for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
154         for(element = list; element; element = element->next) {
155             if(!strcmp(leak_info->mem_info.file_name, element->filename)) {
156                 break;
157             }
158         }
159         if(!element) {
160             element = malloc(sizeof(*element));
161             element->filename = strdup(leak_info->mem_info.file_name);
162             element->allocations = 0;
163             element->allocated = 0;
164             element->next = list;
165             list = element;
166         }
167         element->allocations += 1;
168         element->allocated += leak_info->mem_info.size;
169     }
170     element = malloc(sizeof(*element));
171     element->filename = strdup(__FILE__);
172     element->allocations = own_allocated_memleaks;
173     element->allocated = own_allocated_memleaks * sizeof(struct MemoryLeak);
174     element->next = list;
175     list = element;
176     DESYNCHRONIZE(synchronized);
177     return list;
178 }
179
180 void freeMemoryInfoFiles(struct memoryInfoFiles *files) {
181     struct memoryInfoFiles *next;
182     for(;files;files = next) {
183         next = files->next;
184         free(files->filename);
185         free(files);
186     }
187 }
188
189 struct memoryInfoLines *getMemoryInfoLines(const char *filename) {
190     SYNCHRONIZE(synchronized);
191     struct MemoryLeak *leak_info;
192     struct memoryInfoLines *list = NULL, *element;
193     for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
194         if(stricmp(leak_info->mem_info.file_name, filename)) continue;
195         for(element = list; element; element = element->next) {
196             if(element->line == leak_info->mem_info.line && element->allocate == leak_info->mem_info.size) {
197                 break;
198             }
199         }
200         if(!element) {
201             element = malloc(sizeof(*element));
202             element->line = leak_info->mem_info.line;
203             element->allocations = 0;
204             element->allocate = leak_info->mem_info.size;
205             element->next = list;
206             list = element;
207         }
208         element->allocations++;
209     }
210     if(!stricmp(filename, __FILE__)) {
211         element = malloc(sizeof(*element));
212         element->line = 0;
213         element->allocations = own_allocated_memleaks;
214         element->allocate = sizeof(struct MemoryLeak);
215         element->next = list;
216         list = element;
217     }
218     DESYNCHRONIZE(synchronized);
219     return list;
220 }
221
222 void freeMemoryInfoLines(struct memoryInfoLines *lines) {
223     struct memoryInfoLines *next;
224     for(;lines;lines = next) {
225         next = lines->next;
226         free(lines);
227     }
228 }