From 370ff7a57640ff98cc399317927e8f3c51abad76 Mon Sep 17 00:00:00 2001 From: hniksic Date: Fri, 31 Oct 2003 06:31:56 -0800 Subject: [PATCH] [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. --- src/ChangeLog | 11 ++ src/Makefile.in | 3 +- src/gen-md5.h | 2 + src/http.c | 6 +- src/log.c | 1 + src/log.h | 55 +++++++ src/rbuf.c | 4 +- src/utils.c | 237 +--------------------------- src/utils.h | 2 + src/wget.h | 141 +++++------------ src/xmalloc.c | 305 +++++++++++++++++++++++++++++++++++++ src/xmalloc.h | 79 ++++++++++ windows/Makefile.src | 8 +- windows/Makefile.src.bor | 56 +++---- windows/Makefile.src.mingw | 3 +- windows/README | 5 + windows/wget.dep | 1 + 17 files changed, 546 insertions(+), 373 deletions(-) create mode 100644 src/log.h create mode 100644 src/xmalloc.c create mode 100644 src/xmalloc.h diff --git a/src/ChangeLog b/src/ChangeLog index cf06c544..6b4b222d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,14 @@ +2003-10-31 Hrvoje Niksic + + * 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 * connect.c (sockaddr_set_data): Remove the broken code that diff --git a/src/Makefile.in b/src/Makefile.in index 01e1f93a..705f1310 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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 diff --git a/src/gen-md5.h b/src/gen-md5.h index f5d13c3b..14952644 100644 --- a/src/gen-md5.h +++ b/src/gen-md5.h @@ -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 ()) diff --git a/src/http.c b/src/http.c index 88bb450d..9f523bd1 100644 --- a/src/http.c +++ b/src/http.c @@ -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); diff --git a/src/log.c b/src/log.c index 8ef12520..5e02bac8 100644 --- a/src/log.c +++ b/src/log.c @@ -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; diff --git a/src/log.h b/src/log.h new file mode 100644 index 00000000..ef59aa75 --- /dev/null +++ b/src/log.h @@ -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 */ diff --git a/src/rbuf.c b/src/rbuf.c index 64320454..7b11d67f 100644 --- a/src/rbuf.c +++ b/src/rbuf.c @@ -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); diff --git a/src/utils.c b/src/utils.c index 11c404ae..7a9ca642 100644 --- a/src/utils.c +++ b/src/utils.c @@ -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 * diff --git a/src/utils.h b/src/utils.h index d49847b7..5630c6ca 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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 *)); diff --git a/src/wget.h b/src/wget.h index 496078fe..f3fb26f4 100644 --- a/src/wget.h +++ b/src/wget.h @@ -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__ */ - -/* 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 */ +/* Everything uses this, so include them here directly. */ +#include "xmalloc.h" + +/* 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. */ - -#define STRDUP_ALLOCA(ptr, str) do { \ - (ptr) = (char *)alloca (strlen (str) + 1); \ - strcpy ((ptr), (str)); \ + function correctly. Gcc on Intel platforms has been reported to + offend in this case. */ + +#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. */ diff --git a/src/xmalloc.c b/src/xmalloc.c new file mode 100644 index 00000000..3464cbfe --- /dev/null +++ b/src/xmalloc.c @@ -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 + +#include +#include +#ifdef HAVE_STRING_H +# include +#else /* not HAVE_STRING_H */ +# include +#endif /* not HAVE_STRING_H */ +#include +#include +#include + +#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 */ diff --git a/src/xmalloc.h b/src/xmalloc.h new file mode 100644 index 00000000..220fc312 --- /dev/null +++ b/src/xmalloc.h @@ -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 */ diff --git a/windows/Makefile.src b/windows/Makefile.src index 818d0b8d..27a73f4e 100644 --- a/windows/Makefile.src +++ b/windows/Makefile.src @@ -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 diff --git a/windows/Makefile.src.bor b/windows/Makefile.src.bor index 60f72923..aaba63c3 100644 --- a/windows/Makefile.src.bor +++ b/windows/Makefile.src.bor @@ -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 diff --git a/windows/Makefile.src.mingw b/windows/Makefile.src.mingw index f825ff10..64f73341 100644 --- a/windows/Makefile.src.mingw +++ b/windows/Makefile.src.mingw @@ -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 diff --git a/windows/README b/windows/README index 990005ce..e804a62c 100644 --- a/windows/README +++ b/windows/README @@ -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. diff --git a/windows/wget.dep b/windows/wget.dep index a5b1586b..dae1399a 100644 --- a/windows/wget.dep +++ b/windows/wget.dep @@ -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 -- 2.39.2