1 /* Wrappers around malloc and memory debugging support.
2 Copyright (C) 2003 Free Software Foundation, Inc.
4 This file is part of GNU Wget.
6 GNU Wget 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 GNU Wget 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 Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables. You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL". If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so. If you do not wish to do
28 so, delete this exception statement from your version. */
36 #else /* not HAVE_STRING_H */
38 #endif /* not HAVE_STRING_H */
39 #include <sys/types.h>
50 /* This file implements several wrappers around the basic allocation
51 routines. This is done for two reasons: first, so that the callers
52 of these functions need not check for errors, which is easy to
53 forget. If there is not enough virtual memory for running Wget,
54 something is seriously wrong, and Wget exits with an appropriate
57 The second reason why these are useful is that, if DEBUG_MALLOC is
58 defined, they also provide a handy (if crude) malloc debugging
59 interface that checks memory leaks. */
61 /* Croak the fatal memory error and bail out with non-zero exit
65 memfatal (const char *context, long size)
67 /* Make sure we don't try to store part of the log line, and thus
69 log_set_save_context (0);
70 logprintf (LOG_ALWAYS, _("%s: %s: Cannot allocate %ld bytes.\n"),
71 exec_name, context, size);
75 /* These functions end with _real because they need to be
76 distinguished from the debugging functions, and from the macros.
79 If memory debugging is not turned on, wget.h defines these:
81 #define xmalloc xmalloc_real
82 #define xmalloc0 xmalloc0_real
83 #define xrealloc xrealloc_real
84 #define xstrdup xstrdup_real
87 In case of memory debugging, the definitions are a bit more
88 complex, because we want to provide more information, *and* we want
89 to call the debugging code. (The former is the reason why xmalloc
90 and friends need to be macros in the first place.) Then it looks
93 #define xmalloc(a) xmalloc_debug (a, __FILE__, __LINE__)
94 #define xmalloc0(a) xmalloc0_debug (a, __FILE__, __LINE__)
95 #define xfree(a) xfree_debug (a, __FILE__, __LINE__)
96 #define xrealloc(a, b) xrealloc_debug (a, b, __FILE__, __LINE__)
97 #define xstrdup(a) xstrdup_debug (a, __FILE__, __LINE__)
99 Each of the *_debug function does its magic and calls the real one. */
102 # define STATIC_IF_DEBUG static
104 # define STATIC_IF_DEBUG
107 STATIC_IF_DEBUG void *
108 xmalloc_real (size_t size)
110 void *ptr = malloc (size);
112 memfatal ("malloc", size);
116 STATIC_IF_DEBUG void *
117 xmalloc0_real (size_t size)
119 /* Using calloc can be faster than malloc+memset because some calloc
120 implementations know when they're dealing with zeroed-out memory
121 from the system and can avoid unnecessary memset. */
122 void *ptr = calloc (1, size);
124 memfatal ("calloc", size);
128 STATIC_IF_DEBUG void *
129 xrealloc_real (void *ptr, size_t newsize)
133 /* Not all Un*xes have the feature of realloc() that calling it with
134 a NULL-pointer is the same as malloc(), but it is easy to
137 newptr = realloc (ptr, newsize);
139 newptr = malloc (newsize);
141 memfatal ("realloc", newsize);
145 STATIC_IF_DEBUG char *
146 xstrdup_real (const char *s)
152 copy = malloc (l + 1);
154 memfatal ("strdup", l + 1);
155 memcpy (copy, s, l + 1);
156 #else /* HAVE_STRDUP */
159 memfatal ("strdup", 1 + strlen (s));
160 #endif /* HAVE_STRDUP */
167 /* Crude home-grown routines for debugging some malloc-related
170 * Counting the number of malloc and free invocations, and reporting
171 the "balance", i.e. how many times more malloc was called than it
172 was the case with free.
174 * Making malloc store its entry into a simple array and free remove
175 stuff from that array. At the end, print the pointers which have
176 not been freed, along with the source file and the line number.
177 This also has the side-effect of detecting freeing memory that
180 Note that this kind of memory leak checking strongly depends on
181 every malloc() being followed by a free(), even if the program is
182 about to finish. Wget is careful to free the data structure it
183 allocated in init.c. */
185 static int malloc_count, free_count;
191 } malloc_debug[100000];
193 /* Both register_ptr and unregister_ptr take O(n) operations to run,
194 which can be a real problem. It would be nice to use a hash table
195 for malloc_debug, but the functions in hash.c are not suitable
196 because they can call malloc() themselves. Maybe it would work if
197 the hash table were preallocated to a huge size, and if we set the
198 rehash threshold to 1.0. */
200 /* Register PTR in malloc_debug. Abort if this is not possible
201 (presumably due to the number of current allocations exceeding the
202 size of malloc_debug.) */
205 register_ptr (void *ptr, const char *file, int line)
208 for (i = 0; i < countof (malloc_debug); i++)
209 if (malloc_debug[i].ptr == NULL)
211 malloc_debug[i].ptr = ptr;
212 malloc_debug[i].file = file;
213 malloc_debug[i].line = line;
219 /* Unregister PTR from malloc_debug. Abort if PTR is not present in
220 malloc_debug. (This catches calling free() with a bogus pointer.) */
223 unregister_ptr (void *ptr)
226 for (i = 0; i < countof (malloc_debug); i++)
227 if (malloc_debug[i].ptr == ptr)
229 malloc_debug[i].ptr = NULL;
235 /* Print the malloc debug stats that can be gathered from the above
236 information. Currently this is the count of mallocs, frees, the
237 difference between the two, and the dump of the contents of
238 malloc_debug. The last part are the memory leaks. */
241 print_malloc_debug_stats (void)
244 printf ("\nMalloc: %d\nFree: %d\nBalance: %d\n\n",
245 malloc_count, free_count, malloc_count - free_count);
246 for (i = 0; i < countof (malloc_debug); i++)
247 if (malloc_debug[i].ptr != NULL)
248 printf ("0x%08ld: %s:%d\n", (long)malloc_debug[i].ptr,
249 malloc_debug[i].file, malloc_debug[i].line);
253 xmalloc_debug (size_t size, const char *source_file, int source_line)
255 void *ptr = xmalloc_real (size);
257 register_ptr (ptr, source_file, source_line);
262 xmalloc0_debug (size_t size, const char *source_file, int source_line)
264 void *ptr = xmalloc0_real (size);
266 register_ptr (ptr, source_file, source_line);
271 xrealloc_debug (void *ptr, size_t newsize, const char *source_file, int source_line)
273 void *newptr = xrealloc_real (ptr, newsize);
277 register_ptr (newptr, source_file, source_line);
279 else if (newptr != ptr)
281 unregister_ptr (ptr);
282 register_ptr (newptr, source_file, source_line);
288 xstrdup_debug (const char *s, const char *source_file, int source_line)
290 char *copy = xstrdup_real (s);
292 register_ptr (copy, source_file, source_line);
297 xfree_debug (void *ptr, const char *source_file, int source_line)
299 assert (ptr != NULL);
301 unregister_ptr (ptr);
305 #endif /* DEBUG_MALLOC */