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