]> sjero.net Git - wget/blob - src/xmalloc.c
ebafea1c0479ce19569a5ab962124a82c43c8e09
[wget] / src / xmalloc.c
1 /* Wrappers around malloc and memory debugging support.
2    Copyright (C) 2003-2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
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.
10
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.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
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.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <assert.h>
37
38 #include "wget.h"
39 #include "xmalloc.h"
40 #include "hash.h"               /* for hash_pointer */
41
42 /* This file implements several wrappers around the basic allocation
43    routines.  This is done for two reasons: first, so that the callers
44    of these functions need not check for errors, which is easy to
45    forget.  If there is not enough virtual memory for running Wget,
46    something is seriously wrong, and Wget exits with an appropriate
47    error message.
48
49    The second reason why these are useful is that, if DEBUG_MALLOC is
50    defined, they also provide a handy (if crude) malloc debugging
51    interface that checks for memory leaks.  */
52
53 /* Croak the fatal memory error and bail out with non-zero exit
54    status.  */
55
56 static void
57 memfatal (const char *context, long attempted_size)
58 {
59   /* Make sure we don't try to store part of the log line, and thus
60      call malloc.  */
61   log_set_save_context (false);
62   logprintf (LOG_ALWAYS,
63              _("%s: %s: Failed to allocate %ld bytes; memory exhausted.\n"),
64              exec_name, context, attempted_size);
65   exit (1);
66 }
67
68 /* These functions end with _real because they need to be
69    distinguished from the debugging functions, and from the macros.
70    Explanation follows:
71
72    If memory debugging is not turned on, xmalloc.h defines these:
73
74      #define xmalloc checking_malloc
75      #define xmalloc0 checking_malloc0
76      #define xrealloc checking_realloc
77      #define xstrdup checking_strdup
78      #define xfree checking_free
79
80    In case of memory debugging, the definitions are a bit more
81    complex, because we want to provide more information, *and* we want
82    to call the debugging code.  (The former is the reason why xmalloc
83    and friends need to be macros in the first place.)  Then it looks
84    like this:
85
86      #define xmalloc(a) debugging_malloc (a, __FILE__, __LINE__)
87      #define xmalloc0(a) debugging_malloc0 (a, __FILE__, __LINE__)
88      #define xrealloc(a, b) debugging_realloc (a, b, __FILE__, __LINE__)
89      #define xstrdup(a) debugging_strdup (a, __FILE__, __LINE__)
90      #define xfree(a) debugging_free (a, __FILE__, __LINE__)
91
92    Each of the debugging_* functions does its magic and calls the
93    corresponding checking_* one.  */
94
95 #ifdef DEBUG_MALLOC
96 # define STATIC_IF_DEBUG static
97 #else
98 # define STATIC_IF_DEBUG
99 #endif
100
101 STATIC_IF_DEBUG void *
102 checking_malloc (size_t size)
103 {
104   void *ptr = malloc (size);
105   if (!ptr)
106     memfatal ("malloc", size);
107   return ptr;
108 }
109
110 STATIC_IF_DEBUG void *
111 checking_malloc0 (size_t size)
112 {
113   /* Using calloc can be faster than malloc+memset because some calloc
114      implementations know when they're dealing with zeroed-out memory
115      from the system and can avoid unnecessary memset.  */
116   void *ptr = calloc (1, size);
117   if (!ptr)
118     memfatal ("calloc", size);
119   return ptr;
120 }
121
122 STATIC_IF_DEBUG void *
123 checking_realloc (void *ptr, size_t newsize)
124 {
125   void *newptr;
126
127   /* Not all Un*xes have the feature of realloc() that calling it with
128      a NULL-pointer is the same as malloc(), but it is easy to
129      simulate.  */
130   if (ptr)
131     newptr = realloc (ptr, newsize);
132   else
133     newptr = malloc (newsize);
134   if (!newptr)
135     memfatal ("realloc", newsize);
136   return newptr;
137 }
138
139 STATIC_IF_DEBUG char *
140 checking_strdup (const char *s)
141 {
142   char *copy;
143
144 #ifndef HAVE_STRDUP
145   int l = strlen (s);
146   copy = malloc (l + 1);
147   if (!copy)
148     memfatal ("strdup", l + 1);
149   memcpy (copy, s, l + 1);
150 #else  /* HAVE_STRDUP */
151   copy = strdup (s);
152   if (!copy)
153     memfatal ("strdup", 1 + strlen (s));
154 #endif /* HAVE_STRDUP */
155
156   return copy;
157 }
158
159 STATIC_IF_DEBUG void
160 checking_free (void *ptr)
161 {
162   /* Wget's xfree() must not be passed a NULL pointer.  This is for
163      historical reasons: pre-C89 systems were reported to bomb at
164      free(NULL), and Wget was careful to not call xfree when there was
165      a possibility of PTR being NULL.  (It might have been better to
166      simply have xfree() do nothing if ptr==NULL.)
167
168      Since the code is already written that way, this assert simply
169      enforces the existing constraint.  The benefit is double-checking
170      the logic: code that thinks it can't be passed a NULL pointer,
171      while it in fact can, aborts here.  If you trip on this, either
172      the code has a pointer handling bug or should have called
173      xfree_null instead of xfree.  Correctly written code should never
174      trigger this assertion.
175
176      The downside is that the uninitiated might not expect xfree(NULL)
177      to abort.  If the assertion proves to be too much of a hassle, it
178      can be removed and a check that makes NULL a no-op placed in its
179      stead.  If that is done, xfree_null is no longer needed and
180      should be removed.  */
181   assert (ptr != NULL);
182
183   free (ptr);
184 }
185 \f
186 #ifdef DEBUG_MALLOC
187
188 /* Crude home-grown routines for debugging some malloc-related
189    problems.  Featured:
190
191    * Counting the number of malloc and free invocations, and reporting
192      the "balance", i.e. how many times more malloc was called than it
193      was the case with free.
194
195    * Making malloc store its entry into a simple array and free remove
196      stuff from that array.  At the end, print the pointers which have
197      not been freed, along with the source file and the line number.
198
199    * Checking for "invalid frees", where free is called on a pointer
200      not obtained with malloc, or where the same pointer is freed
201      twice.
202
203    Note that this kind of memory leak checking strongly depends on
204    every malloc() being followed by a free(), even if the program is
205    about to finish.  Wget is careful to free the data structure it
206    allocated in init.c.  */
207
208 static int malloc_count, free_count;
209
210 /* Home-grown hash table of mallocs: */
211
212 #define SZ 100003               /* Prime just over 100,000.  Increase
213                                    it to debug larger Wget runs.  */
214
215 static struct {
216   const void *ptr;
217   const char *file;
218   int line;
219 } malloc_table[SZ];
220
221 /* Find PTR's position in malloc_table.  If PTR is not found, return
222    the next available position.  */
223
224 static inline int
225 ptr_position (const void *ptr)
226 {
227   int i = hash_pointer (ptr) % SZ;
228   for (; malloc_table[i].ptr != NULL; i = (i + 1) % SZ)
229     if (malloc_table[i].ptr == ptr)
230       return i;
231   return i;
232 }
233
234 /* Register PTR in malloc_table.  Abort if this is not possible
235    (presumably due to the number of current allocations exceeding the
236    size of malloc_table.)  */
237
238 static void
239 register_ptr (const void *ptr, const char *file, int line)
240 {
241   int i;
242   if (malloc_count - free_count > SZ)
243     {
244       fprintf (stderr, "Increase SZ to a larger value and recompile.\n");
245       fflush (stderr);
246       abort ();
247     }
248
249   i = ptr_position (ptr);
250   malloc_table[i].ptr = ptr;
251   malloc_table[i].file = file;
252   malloc_table[i].line = line;
253 }
254
255 /* Unregister PTR from malloc_table.  Return false if PTR is not
256    present in malloc_table.  */
257
258 static bool
259 unregister_ptr (void *ptr)
260 {
261   int i = ptr_position (ptr);
262   if (malloc_table[i].ptr == NULL)
263     return false;
264   malloc_table[i].ptr = NULL;
265
266   /* Relocate malloc_table entries immediately following PTR. */
267   for (i = (i + 1) % SZ; malloc_table[i].ptr != NULL; i = (i + 1) % SZ)
268     {
269       const void *ptr2 = malloc_table[i].ptr;
270       /* Find the new location for the key. */
271       int j = hash_pointer (ptr2) % SZ;
272       for (; malloc_table[j].ptr != NULL; j = (j + 1) % SZ)
273         if (ptr2 == malloc_table[j].ptr)
274           /* No need to relocate entry at [i]; it's already at or near
275              its hash position. */
276           goto cont_outer;
277       malloc_table[j] = malloc_table[i];
278       malloc_table[i].ptr = NULL;
279     cont_outer:
280       ;
281     }
282   return true;
283 }
284
285 /* Print the malloc debug stats gathered from the above information.
286    Currently this is the count of mallocs, frees, the difference
287    between the two, and the dump of the contents of malloc_table.  The
288    last part are the memory leaks.  */
289
290 void
291 print_malloc_debug_stats (void)
292 {
293   int i;
294   printf ("\nMalloc:  %d\nFree:    %d\nBalance: %d\n\n",
295           malloc_count, free_count, malloc_count - free_count);
296   for (i = 0; i < SZ; i++)
297     if (malloc_table[i].ptr != NULL)
298       printf ("0x%0*lx: %s:%d\n", PTR_FORMAT (malloc_table[i].ptr),
299               malloc_table[i].file, malloc_table[i].line);
300 }
301
302 void *
303 debugging_malloc (size_t size, const char *source_file, int source_line)
304 {
305   void *ptr = checking_malloc (size);
306   ++malloc_count;
307   register_ptr (ptr, source_file, source_line);
308   return ptr;
309 }
310
311 void *
312 debugging_malloc0 (size_t size, const char *source_file, int source_line)
313 {
314   void *ptr = checking_malloc0 (size);
315   ++malloc_count;
316   register_ptr (ptr, source_file, source_line);
317   return ptr;
318 }
319
320 void *
321 debugging_realloc (void *ptr, size_t newsize, const char *source_file, int source_line)
322 {
323   void *newptr = checking_realloc (ptr, newsize);
324   if (!ptr)
325     {
326       ++malloc_count;
327       register_ptr (newptr, source_file, source_line);
328     }
329   else if (newptr != ptr)
330     {
331       unregister_ptr (ptr);
332       register_ptr (newptr, source_file, source_line);
333     }
334   return newptr;
335 }
336
337 char *
338 debugging_strdup (const char *s, const char *source_file, int source_line)
339 {
340   char *copy = checking_strdup (s);
341   ++malloc_count;
342   register_ptr (copy, source_file, source_line);
343   return copy;
344 }
345
346 void
347 debugging_free (void *ptr, const char *source_file, int source_line)
348 {
349   /* See checking_free for rationale of this abort.  We repeat it here
350      because we can print the file and the line where the offending
351      free occurred.  */
352   if (ptr == NULL)
353     {
354       fprintf (stderr, "%s: xfree(NULL) at %s:%d\n",
355                exec_name, source_file, source_line);
356       abort ();
357     }
358   if (!unregister_ptr (ptr))
359     {
360       fprintf (stderr, "%s: bad xfree(0x%0*lx) at %s:%d\n",
361                exec_name, PTR_FORMAT (ptr), source_file, source_line);
362       abort ();
363     }
364   ++free_count;
365
366   checking_free (ptr);
367 }
368
369 #endif /* DEBUG_MALLOC */