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