4 Copyright (C) 1999-2000 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 /*#define ENABLE_BUFFER_CHECKS*/
29 #define BUFFER_CHECK_SIZE 5
30 #define MIN_BUFFER_CHECK_SIZE 2
40 static GHashTable *data = NULL, *preallocs = NULL;
41 static const char *comment = "";
43 static void add_flow_checks(char *p, unsigned long size)
45 #ifdef ENABLE_BUFFER_CHECKS
48 for (n = 0; n < BUFFER_CHECK_SIZE; n++)
50 for (n = 0; n < BUFFER_CHECK_SIZE; n++)
51 p[size-BUFFER_CHECK_SIZE+n] = n ^ 0x7f;
55 void ig_memcheck_rec(void *key, MEM_REC *rec)
60 if (rec->size != INT_MIN){
63 for (n = 0; n < MIN_BUFFER_CHECK_SIZE; n++)
64 if (p[n] != (n ^ 0x7f))
65 g_error("buffer underflow, file %s line %d!\n", rec->file, rec->line);
67 for (n = 0; n < MIN_BUFFER_CHECK_SIZE; n++)
68 if (p[rec->size-BUFFER_CHECK_SIZE+n] != (n ^ 0x7f))
69 g_error("buffer overflow, file %s line %d!\n", rec->file, rec->line);
73 static void mem_check(void)
75 #ifdef ENABLE_BUFFER_CHECKS
76 g_hash_table_foreach(data, (GHFunc) ig_memcheck_rec, NULL);
80 static void data_add(char *p, int size, const char *file, int line)
84 if (size <= 0 && size != INT_MIN)
85 g_error("size = %d, file %s line %d", size, file, line);
88 data = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
89 preallocs = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal);
92 if (g_hash_table_lookup(data, p) != NULL)
93 g_error("data_add() already malloc()'ed %p (in %s:%d)", p, file, line);
95 rec = g_new(MEM_REC, 1);
96 g_hash_table_insert(data, p, rec);
100 rec->file = g_strdup(file);
102 rec->comment = g_strdup(comment);
105 g_hash_table_insert(preallocs, p-BUFFER_CHECK_SIZE, p);
107 add_flow_checks(p, size);
111 static void data_clear(char *p)
115 if (g_hash_table_lookup(preallocs, p) != NULL)
116 p += BUFFER_CHECK_SIZE;
118 rec = g_hash_table_lookup(data, p);
119 if (rec != NULL && rec->size > 0)
120 memset(p, 'F', rec->size);
123 static void *data_remove(char *p, const char *file, int line)
129 if (g_hash_table_lookup(preallocs, p) != NULL) {
130 g_hash_table_remove(preallocs, p);
131 p += BUFFER_CHECK_SIZE;
134 rec = g_hash_table_lookup(data, p);
136 g_warning("data_remove() data %p not found (in %s:%d)", p, file, line);
137 return p+BUFFER_CHECK_SIZE;
140 g_hash_table_remove(data, p);
142 g_free(rec->comment);
148 void *ig_malloc(int size, const char *file, int line)
152 size += BUFFER_CHECK_SIZE*2;
154 data_add(p, size, file, line);
155 return (void *) (p+BUFFER_CHECK_SIZE);
158 void *ig_malloc0(int size, const char *file, int line)
162 size += BUFFER_CHECK_SIZE*2;
164 data_add(p, size, file, line);
165 return (void *) (p+BUFFER_CHECK_SIZE);
168 void *ig_realloc(void *mem, unsigned long size, const char *file, int line)
170 char *p, *oldmem = mem;
172 size += BUFFER_CHECK_SIZE*2;
173 oldmem -= BUFFER_CHECK_SIZE;
174 data_remove(oldmem, file, line);
175 p = g_realloc(oldmem, size);
176 data_add(p, size, file, line);
177 return (void *) (p+BUFFER_CHECK_SIZE);
180 char *ig_strdup(const char *str, const char *file, int line)
184 if (str == NULL) return NULL;
186 p = ig_malloc(strlen(str)+1, file, line);
192 char *ig_strndup(const char *str, int count, const char *file, int line)
196 if (str == NULL) return NULL;
198 p = ig_malloc(count+1, file, line);
199 strncpy(p, str, count); p[count] = '\0';
204 char *ig_strconcat(const char *file, int line, const char *str, ...)
211 g_return_val_if_fail (str != NULL, NULL);
213 l = 1 + strlen (str);
214 va_start (args, str);
215 s = va_arg (args, char*);
219 s = va_arg (args, char*);
223 concat = ig_malloc(l, file, line);
226 strcat (concat, str);
227 va_start (args, str);
228 s = va_arg (args, char*);
232 s = va_arg (args, char*);
239 char *ig_strdup_printf(const char *file, int line, const char *format, ...)
244 va_start (args, format);
245 buffer = g_strdup_vprintf (format, args);
248 p = ig_malloc(strlen(buffer)+1, file, line);
255 char *ig_strdup_vprintf(const char *file, int line, const char *format, va_list args)
259 buffer = g_strdup_vprintf (format, args);
261 p = ig_malloc(strlen(buffer)+1, file, line);
268 void ig_free(void *p)
272 if (cp == NULL) g_error("ig_free() : trying to free NULL");
274 cp -= BUFFER_CHECK_SIZE;
276 cp = data_remove(cp, "??", 0);
277 if (cp != NULL) g_free(cp);
280 GString *ig_string_new(const char *file, int line, const char *str)
284 ret = g_string_new(str);
285 data_add((void *) ret, INT_MIN, file, line);
289 void ig_string_free(const char *file, int line, GString *str, gboolean freeit)
291 data_remove((void *) str, file, line);
293 data_add(str->str, INT_MIN, file, line);
295 g_string_free(str, freeit);
298 char *ig_strjoinv(const char *file, int line, const char *sepa, char **array)
302 ret = g_strjoinv(sepa, array);
303 data_add(ret, INT_MIN, file, line);
307 char *ig_dirname(const char *file, int line, const char *fname)
311 ret = g_dirname(fname);
312 data_add(ret, INT_MIN, file, line);
316 char *ig_module_build_path(const char *file, int line, const char *dir, const char *module)
320 ret = g_module_build_path(dir, module);
321 data_add(ret, INT_MIN, file, line);
325 void ig_profile_line(void *key, MEM_REC *rec)
329 if (*rec->comment == '\0' &&
330 (strcmp(rec->file, "ig_strdup_printf") == 0 ||
331 strcmp(rec->file, "ig_strdup_vprintf") == 0 ||
332 strcmp(rec->file, "ig_strconcat") == 0 ||
333 strcmp(rec->file, "ig_string_free (free = FALSE)") == 0))
334 data = (char *) rec->p + BUFFER_CHECK_SIZE;
337 fprintf(stderr, "%s:%d %d bytes (%s)\n", rec->file, rec->line, rec->size, data);
340 void ig_mem_profile(void)
342 g_hash_table_foreach(data, (GHFunc) ig_profile_line, NULL);
343 g_hash_table_destroy(data);
344 g_hash_table_destroy(preallocs);
347 static MEM_REC *largest[10];
349 void ig_profile_largest(void *key, MEM_REC *rec)
353 for (n = 0; n < 10; n++)
355 if (largest[n] == NULL || rec->size > largest[n]->size)
357 g_memmove(largest+n+1, largest+n, sizeof(void *)*(9-n));
363 void ig_mem_profile_largest(void)
367 memset(&largest, 0, sizeof(MEM_REC*)*10);
368 /*g_hash_table_foreach(data, (GHFunc) ig_profile_largest, NULL);
370 for (n = 0; n < 10 && largest[n] != NULL; n++)
372 ig_profile_line(NULL, largest[n]);
376 void ig_set_data(const char *data)