[svn] Moved malloc-related code to xmalloc.c. Defined new macros xnew, xnew0,

xnew_array, and xnew0_array.  Created xmalloc.h and log.h to unclutter
wget.h.
This commit is contained in:
hniksic 2003-10-31 06:31:56 -08:00
parent 83e7fe2ca8
commit 370ff7a576
17 changed files with 544 additions and 371 deletions

View File

@ -1,3 +1,14 @@
2003-10-31 Hrvoje Niksic <hniksic@xemacs.org>
* wget.h: Move declarations of malloc and logging code to
xmalloc.h and log.h respectively to unclutter this file.
(STRDUP_ALLOCA): Made it side-effect free.
* xmalloc.h: New files. Define macros xnew, xnew0, xnew_array,
and xnew0_array.
* xmalloc.c: New file. Move the xmalloc routines here.
2003-10-31 Hrvoje Niksic <hniksic@xemacs.org>
* connect.c (sockaddr_set_data): Remove the broken code that

View File

@ -77,7 +77,7 @@ OBJ = $(ALLOCA) cmpt$o connect$o convert$o cookies$o \
headers$o host$o html-parse$o html-url$o http$o init$o \
log$o main$o $(MD5_OBJ) netrc$o progress$o rbuf$o recur$o \
res$o retr$o safe-ctype$o snprintf$o $(SSL_OBJ) url$o \
utils$o version$o
utils$o version$o xmalloc$o
.SUFFIXES:
.SUFFIXES: .c .o ._c ._o
@ -200,3 +200,4 @@ safe-ctype$o: safe-ctype.h
url$o: wget.h sysdep.h options.h safe-ctype.h utils.h url.h host.h hash.h
utils$o: wget.h sysdep.h options.h safe-ctype.h utils.h hash.h
version$o:
xmalloc$o: wget.h xmalloc.h

View File

@ -36,6 +36,8 @@ typedef struct gen_md5_context gen_md5_context;
includes. */
struct gen_md5_context;
#define MD5_HASHLEN 16
#define ALLOCA_MD5_CONTEXT(var_name) \
gen_md5_context *var_name = \
(gen_md5_context *) alloca (gen_md5_context_size ())

View File

@ -1336,9 +1336,9 @@ Accept: %s\r\n\
{
char* last_period_in_local_filename = strrchr(*hs->local_file, '.');
if (last_period_in_local_filename == NULL ||
!(strcasecmp(last_period_in_local_filename, ".htm") == EQ ||
strcasecmp(last_period_in_local_filename, ".html") == EQ))
if (last_period_in_local_filename == NULL
|| !(0 == strcasecmp (last_period_in_local_filename, ".htm")
|| 0 == strcasecmp (last_period_in_local_filename, ".html")))
{
size_t local_filename_len = strlen(*hs->local_file);

View File

@ -62,6 +62,7 @@ so, delete this exception statement from your version. */
#include "wget.h"
#include "utils.h"
#include "log.h"
#ifndef errno
extern int errno;

55
src/log.h Normal file
View File

@ -0,0 +1,55 @@
/* Declarations for log.c.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Wget; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
In addition, as a special exception, the Free Software Foundation
gives permission to link the code of its release of Wget with the
OpenSSL project's "OpenSSL" library (or with modified versions of it
that use the same license as the "OpenSSL" library), and distribute
the linked executables. You must obey the GNU General Public License
in all respects for all of the code used other than "OpenSSL". If you
modify this file, you may extend this exception to your version of the
file, but you are not obligated to do so. If you do not wish to do
so, delete this exception statement from your version. */
#ifndef LOG_H
#define LOG_H
/* Make gcc check for the format of logmsg() and debug_logmsg(). */
#ifdef __GNUC__
# define GCC_FORMAT_ATTR(a, b) __attribute__ ((format (printf, a, b)))
#else /* not __GNUC__ */
# define GCC_FORMAT_ATTR(a, b)
#endif /* not __GNUC__ */
enum log_options { LOG_VERBOSE, LOG_NOTQUIET, LOG_NONVERBOSE, LOG_ALWAYS };
#ifdef HAVE_STDARG_H
void logprintf PARAMS ((enum log_options, const char *, ...))
GCC_FORMAT_ATTR (2, 3);
void debug_logprintf PARAMS ((const char *, ...)) GCC_FORMAT_ATTR (1, 2);
#else /* not HAVE_STDARG_H */
void logprintf ();
void debug_logprintf ();
#endif /* not HAVE_STDARG_H */
void logputs PARAMS ((enum log_options, const char *));
void logflush PARAMS ((void));
void log_set_flush PARAMS ((int));
int log_set_save_context PARAMS ((int));
#endif /* LOG_H */

View File

@ -123,6 +123,8 @@ rbuf_peek (struct rbuf *rbuf, char *store)
return 1;
}
#define MIN(p,q) (((p) <= (q)) ? (p) : (q))
/* Flush RBUF's buffer to WHERE. Flush MAXSIZE bytes at most.
Returns the number of bytes actually copied. If the buffer is
empty, 0 is returned. */
@ -133,7 +135,7 @@ rbuf_flush (struct rbuf *rbuf, char *where, int maxsize)
return 0;
else
{
int howmuch = MINVAL (rbuf->buffer_left, maxsize);
int howmuch = MIN (rbuf->buffer_left, maxsize);
if (where)
memcpy (where, rbuf->buffer_pos, howmuch);

View File

@ -1,6 +1,5 @@
/* Various functions of utilitarian nature.
Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
Free Software Foundation, Inc.
/* Various utility functions.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Wget.
@ -102,238 +101,6 @@ so, delete this exception statement from your version. */
extern int errno;
#endif
/* This section implements several wrappers around the basic
allocation routines. This is done for two reasons: first, so that
the callers of these functions need not consistently check for
errors. If there is not enough virtual memory for running Wget,
something is seriously wrong, and Wget exits with an appropriate
error message.
The second reason why these are useful is that, if DEBUG_MALLOC is
defined, they also provide a handy (if crude) malloc debugging
interface that checks memory leaks. */
/* Croak the fatal memory error and bail out with non-zero exit
status. */
static void
memfatal (const char *what)
{
/* Make sure we don't try to store part of the log line, and thus
call malloc. */
log_set_save_context (0);
logprintf (LOG_ALWAYS, _("%s: %s: Not enough memory.\n"), exec_name, what);
exit (1);
}
/* These functions end with _real because they need to be
distinguished from the debugging functions, and from the macros.
Explanation follows:
If memory debugging is not turned on, wget.h defines these:
#define xmalloc xmalloc_real
#define xrealloc xrealloc_real
#define xstrdup xstrdup_real
#define xfree free
In case of memory debugging, the definitions are a bit more
complex, because we want to provide more information, *and* we want
to call the debugging code. (The former is the reason why xmalloc
and friends need to be macros in the first place.) Then it looks
like this:
#define xmalloc(a) xmalloc_debug (a, __FILE__, __LINE__)
#define xfree(a) xfree_debug (a, __FILE__, __LINE__)
#define xrealloc(a, b) xrealloc_debug (a, b, __FILE__, __LINE__)
#define xstrdup(a) xstrdup_debug (a, __FILE__, __LINE__)
Each of the *_debug function does its magic and calls the real one. */
#ifdef DEBUG_MALLOC
# define STATIC_IF_DEBUG static
#else
# define STATIC_IF_DEBUG
#endif
STATIC_IF_DEBUG void *
xmalloc_real (size_t size)
{
void *ptr = malloc (size);
if (!ptr)
memfatal ("malloc");
return ptr;
}
STATIC_IF_DEBUG void *
xrealloc_real (void *ptr, size_t newsize)
{
void *newptr;
/* Not all Un*xes have the feature of realloc() that calling it with
a NULL-pointer is the same as malloc(), but it is easy to
simulate. */
if (ptr)
newptr = realloc (ptr, newsize);
else
newptr = malloc (newsize);
if (!newptr)
memfatal ("realloc");
return newptr;
}
STATIC_IF_DEBUG char *
xstrdup_real (const char *s)
{
char *copy;
#ifndef HAVE_STRDUP
int l = strlen (s);
copy = malloc (l + 1);
if (!copy)
memfatal ("strdup");
memcpy (copy, s, l + 1);
#else /* HAVE_STRDUP */
copy = strdup (s);
if (!copy)
memfatal ("strdup");
#endif /* HAVE_STRDUP */
return copy;
}
#ifdef DEBUG_MALLOC
/* Crude home-grown routines for debugging some malloc-related
problems. Featured:
* Counting the number of malloc and free invocations, and reporting
the "balance", i.e. how many times more malloc was called than it
was the case with free.
* Making malloc store its entry into a simple array and free remove
stuff from that array. At the end, print the pointers which have
not been freed, along with the source file and the line number.
This also has the side-effect of detecting freeing memory that
was never allocated.
Note that this kind of memory leak checking strongly depends on
every malloc() being followed by a free(), even if the program is
about to finish. Wget is careful to free the data structure it
allocated in init.c. */
static int malloc_count, free_count;
static struct {
char *ptr;
const char *file;
int line;
} malloc_debug[100000];
/* Both register_ptr and unregister_ptr take O(n) operations to run,
which can be a real problem. It would be nice to use a hash table
for malloc_debug, but the functions in hash.c are not suitable
because they can call malloc() themselves. Maybe it would work if
the hash table were preallocated to a huge size, and if we set the
rehash threshold to 1.0. */
/* Register PTR in malloc_debug. Abort if this is not possible
(presumably due to the number of current allocations exceeding the
size of malloc_debug.) */
static void
register_ptr (void *ptr, const char *file, int line)
{
int i;
for (i = 0; i < countof (malloc_debug); i++)
if (malloc_debug[i].ptr == NULL)
{
malloc_debug[i].ptr = ptr;
malloc_debug[i].file = file;
malloc_debug[i].line = line;
return;
}
abort ();
}
/* Unregister PTR from malloc_debug. Abort if PTR is not present in
malloc_debug. (This catches calling free() with a bogus pointer.) */
static void
unregister_ptr (void *ptr)
{
int i;
for (i = 0; i < countof (malloc_debug); i++)
if (malloc_debug[i].ptr == ptr)
{
malloc_debug[i].ptr = NULL;
return;
}
abort ();
}
/* Print the malloc debug stats that can be gathered from the above
information. Currently this is the count of mallocs, frees, the
difference between the two, and the dump of the contents of
malloc_debug. The last part are the memory leaks. */
void
print_malloc_debug_stats (void)
{
int i;
printf ("\nMalloc: %d\nFree: %d\nBalance: %d\n\n",
malloc_count, free_count, malloc_count - free_count);
for (i = 0; i < countof (malloc_debug); i++)
if (malloc_debug[i].ptr != NULL)
printf ("0x%08ld: %s:%d\n", (long)malloc_debug[i].ptr,
malloc_debug[i].file, malloc_debug[i].line);
}
void *
xmalloc_debug (size_t size, const char *source_file, int source_line)
{
void *ptr = xmalloc_real (size);
++malloc_count;
register_ptr (ptr, source_file, source_line);
return ptr;
}
void
xfree_debug (void *ptr, const char *source_file, int source_line)
{
assert (ptr != NULL);
++free_count;
unregister_ptr (ptr);
free (ptr);
}
void *
xrealloc_debug (void *ptr, size_t newsize, const char *source_file, int source_line)
{
void *newptr = xrealloc_real (ptr, newsize);
if (!ptr)
{
++malloc_count;
register_ptr (newptr, source_file, source_line);
}
else if (newptr != ptr)
{
unregister_ptr (ptr);
register_ptr (newptr, source_file, source_line);
}
return newptr;
}
char *
xstrdup_debug (const char *s, const char *source_file, int source_line)
{
char *copy = xstrdup_real (s);
++malloc_count;
register_ptr (copy, source_file, source_line);
return copy;
}
#endif /* DEBUG_MALLOC */
/* Utility function: like xstrdup(), but also lowercases S. */
char *

View File

@ -49,6 +49,8 @@ struct file_memory {
int mmap_p;
};
#define HYPHENP(x) (*(x) == '-' && !*((x) + 1))
struct wget_timer;
char *time_str PARAMS ((time_t *));

View File

@ -97,101 +97,40 @@ so, delete this exception statement from your version. */
# define DEBUGP(x) DO_NOTHING
#endif /* not ENABLE_DEBUG */
/* Make gcc check for the format of logmsg() and debug_logmsg(). */
#ifdef __GNUC__
# define GCC_FORMAT_ATTR(a, b) __attribute__ ((format (printf, a, b)))
#else /* not __GNUC__ */
# define GCC_FORMAT_ATTR(a, b)
#endif /* not __GNUC__ */
/* Everything uses this, so include them here directly. */
#include "xmalloc.h"
/* These are from log.c, but they are used everywhere, so we declare
them here. */
enum log_options { LOG_VERBOSE, LOG_NOTQUIET, LOG_NONVERBOSE, LOG_ALWAYS };
#ifdef HAVE_STDARG_H
void logprintf PARAMS ((enum log_options, const char *, ...))
GCC_FORMAT_ATTR (2, 3);
void debug_logprintf PARAMS ((const char *, ...)) GCC_FORMAT_ATTR (1, 2);
#else /* not HAVE_STDARG_H */
void logprintf ();
void debug_logprintf ();
#endif /* not HAVE_STDARG_H */
void logputs PARAMS ((enum log_options, const char *));
void logflush PARAMS ((void));
void log_set_flush PARAMS ((int));
int log_set_save_context PARAMS ((int));
/* Defined in `utils.c', but used literally everywhere. */
#ifndef DEBUG_MALLOC
#define xmalloc xmalloc_real
#define xrealloc xrealloc_real
#define xstrdup xstrdup_real
#define xfree free
void *xmalloc_real PARAMS ((size_t));
void *xrealloc_real PARAMS ((void *, size_t));
char *xstrdup_real PARAMS ((const char *));
#else /* DEBUG_MALLOC */
#define xmalloc(s) xmalloc_debug (s, __FILE__, __LINE__)
#define xfree(p) xfree_debug (p, __FILE__, __LINE__)
#define xrealloc(p, s) xrealloc_debug (p, s, __FILE__, __LINE__)
#define xstrdup(p) xstrdup_debug (p, __FILE__, __LINE__)
void *xmalloc_debug PARAMS ((size_t, const char *, int));
void xfree_debug PARAMS ((void *, const char *, int));
void *xrealloc_debug PARAMS ((void *, size_t, const char *, int));
char *xstrdup_debug PARAMS ((const char *, const char *, int));
#endif /* DEBUG_MALLOC */
/* Likewise for logging functions. */
#include "log.h"
/* #### Find a better place for this. */
/* The log file to which Wget writes to after HUP. */
#define DEFAULT_LOGFILE "wget-log"
#define MD5_HASHLEN 16
/* Useful macros used across the code: */
/* Is the string a hpyhen-only? */
#define HYPHENP(x) (*(x) == '-' && !*((x) + 1))
/* The number of elements in an array. For example:
static char a[] = "foo"; -- countof(a) == 4 (for terminating \0)
int a[5] = {1, 2}; -- countof(a) == 5
char *a[] = { -- countof(a) == 3
"foo", "bar", "baz"
}; */
#define countof(array) (sizeof (array) / sizeof ((array)[0]))
/* The smaller value of the two. */
#define MINVAL(x, y) ((x) < (y) ? (x) : (y))
/* Zero out a value. */
#define xzero(x) memset (&(x), '\0', sizeof (x))
/* Convert an ASCII hex digit to the corresponding number between 0
and 15. X should be a hexadecimal digit that satisfies isxdigit;
otherwise, the result is undefined. */
#define XDIGIT_TO_NUM(x) ((x) < 'A' ? (x) - '0' : TOUPPER (x) - 'A' + 10)
/* Convert a sequence of ASCII hex digits X and Y to a number betewen
0 and 255. Uses XDIGIT_TO_NUM for conversion of individual
digits. */
#define XDIGIT_TO_NUM(h) ((h) < 'A' ? (h) - '0' : TOUPPER (h) - 'A' + 10)
#define X2DIGITS_TO_NUM(h1, h2) ((XDIGIT_TO_NUM (h1) << 4) + XDIGIT_TO_NUM (h2))
/* The reverse of the above: convert a number in the [0, 16) range to
its ASCII representation in hex. The A-F characters are in upper
case. */
#define XNUM_TO_DIGIT(x) ("0123456789ABCDEF"[x])
/* Like XNUM_TO_DIGIT, but generates lower-case characters. */
#define XNUM_TO_digit(x) ("0123456789abcdef"[x])
/* Returns the number of elements in an array with fixed
initialization. For example:
static char a[] = "foo"; -- countof(a) == 4 (for terminating \0)
int a[5] = {1, 2}; -- countof(a) == 5
char *a[] = { -- countof(a) == 3
"foo", "bar", "baz"
}; */
#define countof(array) (sizeof (array) / sizeof (*(array)))
#define alloca_array(type, size) ((type *) alloca ((size) * sizeof (type)))
the ASCII representation of the corresponding hex digit. The `+ 0'
is so you don't accidentally use it as an lvalue. */
#define XNUM_TO_DIGIT(x) ("0123456789ABCDEF"[x] + 0)
#define XNUM_TO_digit(x) ("0123456789abcdef"[x] + 0)
/* Copy the data delimited with BEG and END to alloca-allocated
storage, and zero-terminate it. Arguments are evaluated only once,
@ -223,12 +162,14 @@ char *xstrdup_debug PARAMS ((const char *, const char *, int));
#define STRDUP_ALLOCA(str) (strcpy ((char *)alloca (strlen (str) + 1), str))
This is because some compilers don't handle alloca() as argument to
function correctly. Gcc under Intel has been reported to offend in
this case. */
function correctly. Gcc on Intel platforms has been reported to
offend in this case. */
#define STRDUP_ALLOCA(ptr, str) do { \
(ptr) = (char *)alloca (strlen (str) + 1); \
strcpy ((ptr), (str)); \
#define STRDUP_ALLOCA(ptr, str) do { \
char **SA_dest = &(ptr); \
const char *SA_src = (str); \
*SA_dest = (char *)alloca (strlen (SA_src) + 1); \
strcpy (*SA_dest, SA_src); \
} while (0)
/* Generally useful if you want to avoid arbitrary size limits but
@ -238,9 +179,8 @@ char *xstrdup_debug PARAMS ((const char *, const char *, int));
will realloc BASEVAR as necessary so that it can hold at least
NEEDED_SIZE objects. The reallocing is done by doubling, which
ensures constant amortized time per element. */
#define DO_REALLOC(basevar, sizevar, needed_size, type) do \
{ \
/* Avoid side-effectualness. */ \
#define DO_REALLOC(basevar, sizevar, needed_size, type) do { \
/* Avoid side effects by prefixing the local vars. */ \
long do_realloc_needed_size = (needed_size); \
long do_realloc_newsize = 0; \
while ((sizevar) < (do_realloc_needed_size)) { \
@ -254,7 +194,7 @@ char *xstrdup_debug PARAMS ((const char *, const char *, int));
} while (0)
/* Free FOO if it is non-NULL. */
#define FREE_MAYBE(foo) do { if (foo) xfree (foo); } while (0)
#define FREE_MAYBE(foo) do { if (foo) xfree ((foo)); } while (0)
extern const char *exec_name;
@ -291,23 +231,22 @@ typedef enum
SSLERRCERTFILE,SSLERRCERTKEY,SSLERRCTXCREATE
} uerr_t;
/* These are not used widely. They should either be removed or used
consistently. */
typedef unsigned char boolean;
#ifndef FALSE
#define FALSE 0
# define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
# define TRUE 1
#endif
/* So we can say strcmp(a, b) == EQ rather than strcmp(a, b) == 0 or
the really awful !strcmp(a, b). */
#define EQ 0
/* For most options, 0 means no limits, but with -p in the picture, that causes
a problem on the maximum recursion depth variable. To retain backwards
compatibility we allow users to consider "0" to be synonymous with "inf" for
-l, but internally infinite recursion is specified by -1 and 0 means to only
retrieve the requisites of a single document. */
/* For most options, 0 means no limits, but with -p in the picture,
that causes a problem on the maximum recursion depth variable. To
retain backwards compatibility we allow users to consider "0" to be
synonymous with "inf" for -l, but internally infinite recursion is
specified by -1 and 0 means to only retrieve the requisites of a
single document. */
#define INFINITE_RECURSION -1
/* In case old systems don't have EAFNOSUPPORT, which we use below. */

305
src/xmalloc.c Normal file
View File

@ -0,0 +1,305 @@
/* Wrappers around malloc and memory debugging support.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Wget; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
In addition, as a special exception, the Free Software Foundation
gives permission to link the code of its release of Wget with the
OpenSSL project's "OpenSSL" library (or with modified versions of it
that use the same license as the "OpenSSL" library), and distribute
the linked executables. You must obey the GNU General Public License
in all respects for all of the code used other than "OpenSSL". If you
modify this file, you may extend this exception to your version of the
file, but you are not obligated to do so. If you do not wish to do
so, delete this exception statement from your version. */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#else /* not HAVE_STRING_H */
# include <strings.h>
#endif /* not HAVE_STRING_H */
#include <sys/types.h>
#include <errno.h>
#include <assert.h>
#include "wget.h"
#include "xmalloc.h"
#ifndef errno
extern int errno;
#endif
/* This file implements several wrappers around the basic allocation
routines. This is done for two reasons: first, so that the callers
of these functions need not check for errors, which is easy to
forget. If there is not enough virtual memory for running Wget,
something is seriously wrong, and Wget exits with an appropriate
error message.
The second reason why these are useful is that, if DEBUG_MALLOC is
defined, they also provide a handy (if crude) malloc debugging
interface that checks memory leaks. */
/* Croak the fatal memory error and bail out with non-zero exit
status. */
static void
memfatal (const char *context, long size)
{
/* Make sure we don't try to store part of the log line, and thus
call malloc. */
log_set_save_context (0);
logprintf (LOG_ALWAYS, _("%s: %s: Cannot allocate %ld bytes.\n"),
exec_name, context, size);
exit (1);
}
/* These functions end with _real because they need to be
distinguished from the debugging functions, and from the macros.
Explanation follows:
If memory debugging is not turned on, wget.h defines these:
#define xmalloc xmalloc_real
#define xmalloc0 xmalloc0_real
#define xrealloc xrealloc_real
#define xstrdup xstrdup_real
#define xfree free
In case of memory debugging, the definitions are a bit more
complex, because we want to provide more information, *and* we want
to call the debugging code. (The former is the reason why xmalloc
and friends need to be macros in the first place.) Then it looks
like this:
#define xmalloc(a) xmalloc_debug (a, __FILE__, __LINE__)
#define xmalloc0(a) xmalloc0_debug (a, __FILE__, __LINE__)
#define xfree(a) xfree_debug (a, __FILE__, __LINE__)
#define xrealloc(a, b) xrealloc_debug (a, b, __FILE__, __LINE__)
#define xstrdup(a) xstrdup_debug (a, __FILE__, __LINE__)
Each of the *_debug function does its magic and calls the real one. */
#ifdef DEBUG_MALLOC
# define STATIC_IF_DEBUG static
#else
# define STATIC_IF_DEBUG
#endif
STATIC_IF_DEBUG void *
xmalloc_real (size_t size)
{
void *ptr = malloc (size);
if (!ptr)
memfatal ("malloc", size);
return ptr;
}
STATIC_IF_DEBUG void *
xmalloc0_real (size_t size)
{
/* Using calloc can be faster than malloc+memset because some calloc
implementations know when they're dealing with zeroed-out memory
from the system and can avoid unnecessary memset. */
void *ptr = calloc (1, size);
if (!ptr)
memfatal ("calloc", size);
return ptr;
}
STATIC_IF_DEBUG void *
xrealloc_real (void *ptr, size_t newsize)
{
void *newptr;
/* Not all Un*xes have the feature of realloc() that calling it with
a NULL-pointer is the same as malloc(), but it is easy to
simulate. */
if (ptr)
newptr = realloc (ptr, newsize);
else
newptr = malloc (newsize);
if (!newptr)
memfatal ("realloc", newsize);
return newptr;
}
STATIC_IF_DEBUG char *
xstrdup_real (const char *s)
{
char *copy;
#ifndef HAVE_STRDUP
int l = strlen (s);
copy = malloc (l + 1);
if (!copy)
memfatal ("strdup", l + 1);
memcpy (copy, s, l + 1);
#else /* HAVE_STRDUP */
copy = strdup (s);
if (!copy)
memfatal ("strdup", 1 + strlen (s));
#endif /* HAVE_STRDUP */
return copy;
}
#ifdef DEBUG_MALLOC
/* Crude home-grown routines for debugging some malloc-related
problems. Featured:
* Counting the number of malloc and free invocations, and reporting
the "balance", i.e. how many times more malloc was called than it
was the case with free.
* Making malloc store its entry into a simple array and free remove
stuff from that array. At the end, print the pointers which have
not been freed, along with the source file and the line number.
This also has the side-effect of detecting freeing memory that
was never allocated.
Note that this kind of memory leak checking strongly depends on
every malloc() being followed by a free(), even if the program is
about to finish. Wget is careful to free the data structure it
allocated in init.c. */
static int malloc_count, free_count;
static struct {
char *ptr;
const char *file;
int line;
} malloc_debug[100000];
/* Both register_ptr and unregister_ptr take O(n) operations to run,
which can be a real problem. It would be nice to use a hash table
for malloc_debug, but the functions in hash.c are not suitable
because they can call malloc() themselves. Maybe it would work if
the hash table were preallocated to a huge size, and if we set the
rehash threshold to 1.0. */
/* Register PTR in malloc_debug. Abort if this is not possible
(presumably due to the number of current allocations exceeding the
size of malloc_debug.) */
static void
register_ptr (void *ptr, const char *file, int line)
{
int i;
for (i = 0; i < countof (malloc_debug); i++)
if (malloc_debug[i].ptr == NULL)
{
malloc_debug[i].ptr = ptr;
malloc_debug[i].file = file;
malloc_debug[i].line = line;
return;
}
abort ();
}
/* Unregister PTR from malloc_debug. Abort if PTR is not present in
malloc_debug. (This catches calling free() with a bogus pointer.) */
static void
unregister_ptr (void *ptr)
{
int i;
for (i = 0; i < countof (malloc_debug); i++)
if (malloc_debug[i].ptr == ptr)
{
malloc_debug[i].ptr = NULL;
return;
}
abort ();
}
/* Print the malloc debug stats that can be gathered from the above
information. Currently this is the count of mallocs, frees, the
difference between the two, and the dump of the contents of
malloc_debug. The last part are the memory leaks. */
void
print_malloc_debug_stats (void)
{
int i;
printf ("\nMalloc: %d\nFree: %d\nBalance: %d\n\n",
malloc_count, free_count, malloc_count - free_count);
for (i = 0; i < countof (malloc_debug); i++)
if (malloc_debug[i].ptr != NULL)
printf ("0x%08ld: %s:%d\n", (long)malloc_debug[i].ptr,
malloc_debug[i].file, malloc_debug[i].line);
}
void *
xmalloc_debug (size_t size, const char *source_file, int source_line)
{
void *ptr = xmalloc_real (size);
++malloc_count;
register_ptr (ptr, source_file, source_line);
return ptr;
}
void *
xmalloc0_debug (size_t size, const char *source_file, int source_line)
{
void *ptr = xmalloc0_real (size);
++malloc_count;
register_ptr (ptr, source_file, source_line);
return ptr;
}
void *
xrealloc_debug (void *ptr, size_t newsize, const char *source_file, int source_line)
{
void *newptr = xrealloc_real (ptr, newsize);
if (!ptr)
{
++malloc_count;
register_ptr (newptr, source_file, source_line);
}
else if (newptr != ptr)
{
unregister_ptr (ptr);
register_ptr (newptr, source_file, source_line);
}
return newptr;
}
char *
xstrdup_debug (const char *s, const char *source_file, int source_line)
{
char *copy = xstrdup_real (s);
++malloc_count;
register_ptr (copy, source_file, source_line);
return copy;
}
void
xfree_debug (void *ptr, const char *source_file, int source_line)
{
assert (ptr != NULL);
++free_count;
unregister_ptr (ptr);
free (ptr);
}
#endif /* DEBUG_MALLOC */

79
src/xmalloc.h Normal file
View File

@ -0,0 +1,79 @@
/* xmalloc.c declarations.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Wget; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
In addition, as a special exception, the Free Software Foundation
gives permission to link the code of its release of Wget with the
OpenSSL project's "OpenSSL" library (or with modified versions of it
that use the same license as the "OpenSSL" library), and distribute
the linked executables. You must obey the GNU General Public License
in all respects for all of the code used other than "OpenSSL". If you
modify this file, you may extend this exception to your version of the
file, but you are not obligated to do so. If you do not wish to do
so, delete this exception statement from your version. */
#ifndef XMALLOC_H
#define XMALLOC_H
/* When DEBUG_MALLOC is not defined (which is normally the case), the
allocation functions directly map to *_real wrappers. In the
DEBUG_MALLOC mode, they also record the file and line where the
offending malloc/free/... was invoked. */
#ifndef DEBUG_MALLOC
#define xmalloc xmalloc_real
#define xmalloc0 xmalloc0_real
#define xrealloc xrealloc_real
#define xstrdup xstrdup_real
#define xfree free
void *xmalloc_real PARAMS ((size_t));
void *xmalloc0_real PARAMS ((size_t));
void *xrealloc_real PARAMS ((void *, size_t));
char *xstrdup_real PARAMS ((const char *));
#else /* DEBUG_MALLOC */
#define xmalloc(s) xmalloc_debug (s, __FILE__, __LINE__)
#define xmalloc0(s) xmalloc0_debug (s, __FILE__, __LINE__)
#define xfree(p) xfree_debug (p, __FILE__, __LINE__)
#define xrealloc(p, s) xrealloc_debug (p, s, __FILE__, __LINE__)
#define xstrdup(p) xstrdup_debug (p, __FILE__, __LINE__)
void *xmalloc_debug PARAMS ((size_t, const char *, int));
void *xmalloc0_debug PARAMS ((size_t, const char *, int));
void xfree_debug PARAMS ((void *, const char *, int));
void *xrealloc_debug PARAMS ((void *, size_t, const char *, int));
char *xstrdup_debug PARAMS ((const char *, const char *, int));
#endif /* DEBUG_MALLOC */
/* Macros that interface to malloc, but know about type sizes, and
cast the result to the appropriate type. The casts are not
necessary in standard C, but Wget performs them anyway for the sake
of pre-standard environments and possibly C++. */
#define xnew(type) ((type *) xmalloc (sizeof (type)))
#define xnew0(type) ((type *) xmalloc0 (sizeof (type)))
#define xnew_array(type, len) ((type *) xmalloc ((len) * sizeof (type)))
#define xnew0_array(type, len) ((type *) xmalloc0 ((len) * sizeof (type)))
#define alloca_array(type, size) ((type *) alloca ((size) * sizeof (type)))
#endif /* XMALLOC_H */

View File

@ -66,14 +66,14 @@ RM = del
SRC = cmpt.c safe-ctype.c convert.c connect.c host.c http.c netrc.c \
ftp-basic.c ftp.c ftp-ls.c ftp-opie.c getopt.c hash.c headers.c \
html-parse.c html-url.c progress.c retr.c recur.c res.c url.c cookies.c \
init.c utils.c main.c version.c mswindows.c gen-md5.c \
gnu-md5.c rbuf.c log.c $(SSLSRC)
init.c utils.c main.c version.c xmalloc.c mswindows.c \
gen-md5.c gnu-md5.c rbuf.c log.c $(SSLSRC)
OBJ = cmpt$o safe-ctype$o convert$o connect$o host$o http$o netrc$o \
ftp-basic$o ftp$o ftp-ls$o ftp-opie$o getopt$o hash$o headers$o \
html-parse$o html-url$o progress$o retr$o recur$o res$o url$o cookies$o \
init$o utils$o main$o version$o mswindows$o gen-md5$o gnu-md5$o\
rbuf$o log$o $(SSLOBJ)
init$o utils$o main$o version$o xmalloc$o mswindows$o \
gen-md5$o gnu-md5$o rbuf$o log$o $(SSLOBJ)
.SUFFIXES: .c .obj

View File

@ -12,7 +12,8 @@ OBJS=cmpt.obj connect.obj convert.obj ftp.obj ftp-basic.obj \
ftp-ls.obj ftp-opie.obj getopt.obj headers.obj host.obj html-parse.obj html-url.obj \
http.obj init.obj log.obj main.obj gnu-md5.obj netrc.obj rbuf.obj \
safe-ctype.obj hash.obj progress.obj gen-md5.obj cookies.obj \
recur.obj res.obj retr.obj url.obj utils.obj version.obj mswindows.obj
recur.obj res.obj retr.obj url.obj utils.obj version.obj xmalloc.obj \
mswindows.obj
LIBDIR=$(MAKEDIR)\..\lib
@ -20,37 +21,38 @@ wget.exe: $(OBJS)
$(LINK) @&&|
$(LFLAGS) -Tpe -ap -c +
$(LIBDIR)\c0x32.obj+
cmpt.obj
connect.obj+
convert.obj+
cookies.obj+
hash.obj+
safe-ctype.obj+
version.obj+
utils.obj+
url.obj+
retr.obj+
res.obj+
recur.obj+
rbuf.obj+
progress.obj+
netrc.obj+
mswindows.obj+
gnu-md5.obj+
ftp-basic.obj+
ftp-ls.obj+
ftp-opie.obj+
ftp.obj+
gen-md5.obj+
main.obj+
log.obj+
init.obj+
http.obj+
getopt.obj+
gnu-md5.obj+
hash.obj+
headers.obj+
host.obj+
html-parse.obj+
html-url.obj+
host.obj+
headers.obj+
getopt.obj+
ftp-opie.obj+
ftp-ls.obj+
ftp-basic.obj+
ftp.obj+
connect.obj+
cmpt.obj
http.obj+
init.obj+
log.obj+
main.obj+
mswindows.obj+
netrc.obj+
progress.obj+
rbuf.obj+
recur.obj+
res.obj+
retr.obj+
safe-ctype.obj+
url.obj+
utils.obj+
version.obj+
xmalloc.obj+
$<,$*
$(LIBDIR)\import32.lib+
$(LIBDIR)\cw32.lib

View File

@ -25,7 +25,8 @@ OBJS=cmpt${OBJ_EXT} convert${OBJ_EXT} connect${OBJ_EXT} ftp${OBJ_EXT} ftp-basic$
ftp-ls${OBJ_EXT} ftp-opie${OBJ_EXT} getopt${OBJ_EXT} headers${OBJ_EXT} host${OBJ_EXT} html-parse${OBJ_EXT} html-url${OBJ_EXT} \
http${OBJ_EXT} init${OBJ_EXT} log${OBJ_EXT} main${OBJ_EXT} gnu-md5${OBJ_EXT} netrc${OBJ_EXT} rbuf${OBJ_EXT} \
safe-ctype${OBJ_EXT} hash${OBJ_EXT} progress${OBJ_EXT} gen-md5${OBJ_EXT} cookies${OBJ_EXT} \
recur${OBJ_EXT} res${OBJ_EXT} retr${OBJ_EXT} url${OBJ_EXT} utils${OBJ_EXT} version${OBJ_EXT} mswindows${OBJ_EXT}
recur${OBJ_EXT} res${OBJ_EXT} retr${OBJ_EXT} url${OBJ_EXT} utils${OBJ_EXT} \
version${OBJ_EXT} xmalloc${OBJ_EXT} mswindows${OBJ_EXT}
ifdef SSL
## OPENSSL_PATH is the OpenSSL installed directory

View File

@ -46,3 +46,8 @@ Windows contributors:
* Douglas E. Wegscheid -- maintains configure.bat and various Windows
makefiles.
* Herold Heiko -- numerous build reports and fixes.
* Gisle Vanem -- many Windows-related improvements to the source and
the build system.

View File

@ -32,3 +32,4 @@ snprintf$o: snprintf.c config.h safe-ctype.h
url$o: url.c config.h wget.h sysdep.h mswindows.h options.h safe-ctype.h utils.h url.h host.h hash.h
utils$o: utils.c config.h wget.h sysdep.h mswindows.h options.h safe-ctype.h utils.h hash.h
version$o: version.c
xmalloc$o: wget.h xmalloc.h