(thanks to the people reading git and excessively exploiting this bug... It was undet...
[NeonServV5.git] / src / memoryDebug.c
1 /* memoryDebug.c - NeonServ v5.6
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 #include "tools.h"
21
22 #define FILE_NAME_LENGTH  256
23 #define OUTPUT_FILE "leak_info.txt"
24
25 #undef malloc
26 #undef calloc
27 #undef strdup
28 #undef free
29
30 struct MemoryNode {
31 void *address;
32 unsigned int size;
33 char file_name[FILE_NAME_LENGTH];
34 unsigned int line;
35 };
36
37 struct MemoryLeak {
38 struct MemoryNode mem_info;
39 struct MemoryLeak *next;
40 };
41
42 #ifdef HAVE_THREADS
43 static pthread_mutex_t synchronized;
44 #endif
45
46 static struct MemoryLeak *ptr_start = NULL;
47
48 static unsigned int own_allocated_memleaks = 0;
49
50 static void add_mem_info(void * mem_ref, unsigned int size, const char *file, unsigned int line);
51 static void remove_mem_info(void * mem_ref);
52
53 void *xmalloc(unsigned int size, const char *file, unsigned int line) {
54     void *ptr = malloc(size);
55     if (ptr != NULL) {
56         add_mem_info(ptr, size, file, line);
57     }
58     return ptr;
59 }
60
61 void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line) {
62     void *ptr = calloc(elements, size);
63     if(ptr != NULL) {
64         add_mem_info(ptr, (elements * size), file, line);
65     }
66     return ptr;
67 }
68
69 char *xstrdup(const char *data, const char *file, unsigned int line) {
70     int len = strlen(data)+1;
71     char *ptr = malloc(len);
72     if(ptr != NULL) {
73         strcpy(ptr, data);
74         add_mem_info(ptr, len, file, line);
75     }
76     return ptr;
77 }
78
79 void xfree(void *mem_ref) {
80     remove_mem_info(mem_ref);
81     free(mem_ref);
82 }
83
84 static void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line) {
85     #ifdef HAVE_THREADS
86     pthread_mutex_lock(&synchronized);
87     #endif
88     struct MemoryLeak *mem_leak_info = malloc(sizeof(*mem_leak_info));
89     own_allocated_memleaks++;
90     mem_leak_info->mem_info.address = mem_ref;
91     mem_leak_info->mem_info.size = size;
92     strcpy(mem_leak_info->mem_info.file_name, file);    
93     mem_leak_info->mem_info.line = line;
94     mem_leak_info->next = ptr_start;
95     ptr_start = mem_leak_info;
96     #ifdef HAVE_THREADS
97     pthread_mutex_unlock(&synchronized);
98     #endif
99 }
100
101 static void remove_mem_info(void *mem_ref) {
102     #ifdef HAVE_THREADS
103     pthread_mutex_lock(&synchronized);
104     #endif
105     struct MemoryLeak *leak_info, *next, *prev = NULL;
106     for(leak_info = ptr_start; leak_info; leak_info = next) {
107         next = leak_info->next;
108         if (leak_info->mem_info.address == mem_ref) {
109             if(prev)
110                 prev->next = next;
111             else
112                 ptr_start = next;
113             own_allocated_memleaks--;
114             free(leak_info);
115             break;
116         } else 
117             prev = leak_info;
118     }
119     #ifdef HAVE_THREADS
120     pthread_mutex_unlock(&synchronized);
121     #endif
122 }
123
124 void initMemoryDebug() {
125     THREAD_MUTEX_INIT(synchronized);
126 }
127
128 struct memoryInfoFiles *getMemoryInfoFiles() {
129     #ifdef HAVE_THREADS
130     pthread_mutex_lock(&synchronized);
131     #endif
132     struct MemoryLeak *leak_info;
133     struct memoryInfoFiles *list = NULL, *element;
134     for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
135         for(element = list; element; element = element->next) {
136             if(!strcmp(leak_info->mem_info.file_name, element->filename)) {
137                 break;
138             }
139         }
140         if(!element) {
141             element = malloc(sizeof(*element));
142             element->filename = strdup(leak_info->mem_info.file_name);
143             element->allocations = 0;
144             element->allocated = 0;
145             element->next = list;
146             list = element;
147         }
148         element->allocations += 1;
149         element->allocated += leak_info->mem_info.size;
150     }
151     element = malloc(sizeof(*element));
152     element->filename = strdup(__FILE__);
153     element->allocations = own_allocated_memleaks;
154     element->allocated = own_allocated_memleaks * sizeof(struct MemoryLeak);
155     element->next = list;
156     list = element;
157     #ifdef HAVE_THREADS
158     pthread_mutex_unlock(&synchronized);
159     #endif
160     return list;
161 }
162
163 void freeMemoryInfoFiles(struct memoryInfoFiles *files) {
164     struct memoryInfoFiles *next;
165     for(;files;files = next) {
166         next = files->next;
167         free(files->filename);
168         free(files);
169     }
170 }
171
172 struct memoryInfoLines *getMemoryInfoLines(const char *filename) {
173     #ifdef HAVE_THREADS
174     pthread_mutex_lock(&synchronized);
175     #endif
176     struct MemoryLeak *leak_info;
177     struct memoryInfoLines *list = NULL, *element;
178     for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
179         if(stricmp(leak_info->mem_info.file_name, filename)) continue;
180         for(element = list; element; element = element->next) {
181             if(element->line == leak_info->mem_info.line && element->allocate == leak_info->mem_info.size) {
182                 break;
183             }
184         }
185         if(!element) {
186             element = malloc(sizeof(*element));
187             element->line = leak_info->mem_info.line;
188             element->allocations = 0;
189             element->allocate = leak_info->mem_info.size;
190             element->next = list;
191             list = element;
192         }
193         element->allocations++;
194     }
195     if(!stricmp(filename, __FILE__)) {
196         element = malloc(sizeof(*element));
197         element->line = 0;
198         element->allocations = own_allocated_memleaks;
199         element->allocate = sizeof(struct MemoryLeak);
200         element->next = list;
201         list = element;
202     }
203     #ifdef HAVE_THREADS
204     pthread_mutex_unlock(&synchronized);
205     #endif
206     return list;
207 }
208
209 void freeMemoryInfoLines(struct memoryInfoLines *lines) {
210     struct memoryInfoLines *next;
211     for(;lines;lines = next) {
212         next = lines->next;
213         free(lines);
214     }
215 }