~ubuntu-branches/ubuntu/trusty/wget/trusty-updates

« back to all changes in this revision

Viewing changes to src/xmalloc.c

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2009-12-12 08:15:59 UTC
  • mfrom: (2.1.5 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091212081559-mvccl4kzdqb138y3
Tags: 1.12-1.1ubuntu1
* Merge from debian testing, remaining changes:
  - Add wget-udeb to ship wget.gnu as alternative to busybox wget
    implementation.
* Keep build dependencies in main:
  - debian/control: remove info2man build-dep
  - debian/patches/00list: disable wget-infopod_generated_manpage.dpatch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Wrappers around malloc and memory debugging support.
2
 
   Copyright (C) 2003, 2004, 2005, 2006, 2007,
3
 
   2008 Free Software Foundation, 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
 
 
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 */