mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
[svn] Improve built-in memory debugger.
This commit is contained in:
parent
6da4142b3b
commit
7c044778bc
@ -1,3 +1,38 @@
|
|||||||
|
2005-03-20 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
|
* url.c (unescape_single_char): New function.
|
||||||
|
(url_escape_dir): Use it to unescape slashes in directory
|
||||||
|
components.
|
||||||
|
(url_string): Escape unsafe chars in host name, except for the ':'
|
||||||
|
charaters, which can appear in IPv6 addresses.
|
||||||
|
|
||||||
|
* main.c (main): Don't access the cookie jar directly.
|
||||||
|
|
||||||
|
* log.c (escnonprint_internal): Correctly calculate the needed
|
||||||
|
string size. Don't forget the buffer's new size after having
|
||||||
|
reallocated it.
|
||||||
|
(log_cleanup): New function. Free the escnonprint ring data.
|
||||||
|
|
||||||
|
* init.c (cleanup): Don't free the cookie jar explicitly, it is
|
||||||
|
now done by http_cleanup.
|
||||||
|
(cleanup): opt.user_headers is now a vector, free it with
|
||||||
|
free_vec.
|
||||||
|
|
||||||
|
* http.c (gethttp): Make sure to free the request data, the status
|
||||||
|
message, and the response data before returning from the function.
|
||||||
|
(save_cookies): New function.
|
||||||
|
(http_cleanup): Free the cookie jar here.
|
||||||
|
|
||||||
|
* hash.c: Renamed string_hash to hash_string and ptrhash to
|
||||||
|
hash_pointer. Exported hash_pointer.
|
||||||
|
|
||||||
|
* xmalloc.c: Organized malloc_table (previously malloc_debug) as a
|
||||||
|
simple EQ hash table. register_ptr and unregister_ptr are now of
|
||||||
|
O(1) complexity.
|
||||||
|
|
||||||
|
* xmalloc.c: Renamed "*_debug" to debugging_* and "*_real" to
|
||||||
|
checking_*.
|
||||||
|
|
||||||
2005-03-12 Hrvoje Niksic <hniksic@xemacs.org>
|
2005-03-12 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
* utils.c (debug_test_md5): Moved to gen-md5.c.
|
* utils.c (debug_test_md5): Moved to gen-md5.c.
|
||||||
|
@ -96,5 +96,6 @@ void register_redirection PARAMS ((const char *, const char *));
|
|||||||
void register_html PARAMS ((const char *, const char *));
|
void register_html PARAMS ((const char *, const char *));
|
||||||
void register_delete_file PARAMS ((const char *));
|
void register_delete_file PARAMS ((const char *));
|
||||||
void convert_all_links PARAMS ((void));
|
void convert_all_links PARAMS ((void));
|
||||||
|
void convert_cleanup PARAMS ((void));
|
||||||
|
|
||||||
#endif /* CONVERT_H */
|
#endif /* CONVERT_H */
|
||||||
|
29
src/hash.c
29
src/hash.c
@ -244,8 +244,7 @@ prime_size (int size, int *prime_offset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long ptrhash PARAMS ((const void *));
|
static int cmp_pointer PARAMS ((const void *, const void *));
|
||||||
static int ptrcmp PARAMS ((const void *, const void *));
|
|
||||||
|
|
||||||
/* Create a hash table with hash function HASH_FUNCTION and test
|
/* Create a hash table with hash function HASH_FUNCTION and test
|
||||||
function TEST_FUNCTION. The table is empty (its count is 0), but
|
function TEST_FUNCTION. The table is empty (its count is 0), but
|
||||||
@ -279,8 +278,8 @@ hash_table_new (int items,
|
|||||||
int size;
|
int size;
|
||||||
struct hash_table *ht = xnew (struct hash_table);
|
struct hash_table *ht = xnew (struct hash_table);
|
||||||
|
|
||||||
ht->hash_function = hash_function ? hash_function : ptrhash;
|
ht->hash_function = hash_function ? hash_function : hash_pointer;
|
||||||
ht->test_function = test_function ? test_function : ptrcmp;
|
ht->test_function = test_function ? test_function : cmp_pointer;
|
||||||
|
|
||||||
/* If the size of struct hash_table ever becomes a concern, this
|
/* If the size of struct hash_table ever becomes a concern, this
|
||||||
field can go. (Wget doesn't create many hashes.) */
|
field can go. (Wget doesn't create many hashes.) */
|
||||||
@ -596,8 +595,8 @@ hash_table_count (const struct hash_table *ht)
|
|||||||
We used to use the popular hash function from the Dragon Book, but
|
We used to use the popular hash function from the Dragon Book, but
|
||||||
this one seems to perform much better. */
|
this one seems to perform much better. */
|
||||||
|
|
||||||
unsigned long
|
static unsigned long
|
||||||
string_hash (const void *key)
|
hash_string (const void *key)
|
||||||
{
|
{
|
||||||
const char *p = key;
|
const char *p = key;
|
||||||
unsigned int h = *p;
|
unsigned int h = *p;
|
||||||
@ -611,8 +610,8 @@ string_hash (const void *key)
|
|||||||
|
|
||||||
/* Frontend for strcmp usable for hash tables. */
|
/* Frontend for strcmp usable for hash tables. */
|
||||||
|
|
||||||
int
|
static int
|
||||||
string_cmp (const void *s1, const void *s2)
|
cmp_string (const void *s1, const void *s2)
|
||||||
{
|
{
|
||||||
return !strcmp ((const char *)s1, (const char *)s2);
|
return !strcmp ((const char *)s1, (const char *)s2);
|
||||||
}
|
}
|
||||||
@ -623,7 +622,7 @@ string_cmp (const void *s1, const void *s2)
|
|||||||
struct hash_table *
|
struct hash_table *
|
||||||
make_string_hash_table (int items)
|
make_string_hash_table (int items)
|
||||||
{
|
{
|
||||||
return hash_table_new (items, string_hash, string_cmp);
|
return hash_table_new (items, hash_string, cmp_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -632,10 +631,10 @@ make_string_hash_table (int items)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Like string_hash, but produce the same hash regardless of the case. */
|
/* Like hash_string, but produce the same hash regardless of the case. */
|
||||||
|
|
||||||
static unsigned long
|
static unsigned long
|
||||||
string_hash_nocase (const void *key)
|
hash_string_nocase (const void *key)
|
||||||
{
|
{
|
||||||
const char *p = key;
|
const char *p = key;
|
||||||
unsigned int h = TOLOWER (*p);
|
unsigned int h = TOLOWER (*p);
|
||||||
@ -661,7 +660,7 @@ string_cmp_nocase (const void *s1, const void *s2)
|
|||||||
struct hash_table *
|
struct hash_table *
|
||||||
make_nocase_string_hash_table (int items)
|
make_nocase_string_hash_table (int items)
|
||||||
{
|
{
|
||||||
return hash_table_new (items, string_hash_nocase, string_cmp_nocase);
|
return hash_table_new (items, hash_string_nocase, string_cmp_nocase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hashing of numeric values, such as pointers and integers.
|
/* Hashing of numeric values, such as pointers and integers.
|
||||||
@ -671,8 +670,8 @@ make_nocase_string_hash_table (int items)
|
|||||||
spreading of values and doesn't need to know the hash table size to
|
spreading of values and doesn't need to know the hash table size to
|
||||||
work (unlike the very popular Knuth's multiplication hash). */
|
work (unlike the very popular Knuth's multiplication hash). */
|
||||||
|
|
||||||
static unsigned long
|
unsigned long
|
||||||
ptrhash (const void *ptr)
|
hash_pointer (const void *ptr)
|
||||||
{
|
{
|
||||||
unsigned long key = (unsigned long)ptr;
|
unsigned long key = (unsigned long)ptr;
|
||||||
key += (key << 12);
|
key += (key << 12);
|
||||||
@ -697,7 +696,7 @@ ptrhash (const void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ptrcmp (const void *ptr1, const void *ptr2)
|
cmp_pointer (const void *ptr1, const void *ptr2)
|
||||||
{
|
{
|
||||||
return ptr1 == ptr2;
|
return ptr1 == ptr2;
|
||||||
}
|
}
|
||||||
|
28
src/hash.h
28
src/hash.h
@ -30,18 +30,6 @@ so, delete this exception statement from your version. */
|
|||||||
#ifndef HASH_H
|
#ifndef HASH_H
|
||||||
#define HASH_H
|
#define HASH_H
|
||||||
|
|
||||||
/* From XEmacs, and hence from Dragon book. */
|
|
||||||
|
|
||||||
#define GOOD_HASH 65599 /* prime number just over 2^16; Dragon book, p. 435 */
|
|
||||||
#define HASH2(a,b) (GOOD_HASH * (a) + (b))
|
|
||||||
#define HASH3(a,b,c) (GOOD_HASH * HASH2 (a,b) + (c))
|
|
||||||
#define HASH4(a,b,c,d) (GOOD_HASH * HASH3 (a,b,c) + (d))
|
|
||||||
#define HASH5(a,b,c,d,e) (GOOD_HASH * HASH4 (a,b,c,d) + (e))
|
|
||||||
#define HASH6(a,b,c,d,e,f) (GOOD_HASH * HASH5 (a,b,c,d,e) + (f))
|
|
||||||
#define HASH7(a,b,c,d,e,f,g) (GOOD_HASH * HASH6 (a,b,c,d,e,f) + (g))
|
|
||||||
#define HASH8(a,b,c,d,e,f,g,h) (GOOD_HASH * HASH7 (a,b,c,d,e,f,g) + (h))
|
|
||||||
#define HASH9(a,b,c,d,e,f,g,h,i) (GOOD_HASH * HASH8 (a,b,c,d,e,f,g,h) + (i))
|
|
||||||
|
|
||||||
struct hash_table;
|
struct hash_table;
|
||||||
|
|
||||||
struct hash_table *hash_table_new PARAMS ((int,
|
struct hash_table *hash_table_new PARAMS ((int,
|
||||||
@ -64,9 +52,21 @@ void hash_table_map PARAMS ((struct hash_table *,
|
|||||||
void *));
|
void *));
|
||||||
int hash_table_count PARAMS ((const struct hash_table *));
|
int hash_table_count PARAMS ((const struct hash_table *));
|
||||||
|
|
||||||
unsigned long string_hash PARAMS ((const void *));
|
|
||||||
int string_cmp PARAMS ((const void *, const void *));
|
|
||||||
struct hash_table *make_string_hash_table PARAMS ((int));
|
struct hash_table *make_string_hash_table PARAMS ((int));
|
||||||
struct hash_table *make_nocase_string_hash_table PARAMS ((int));
|
struct hash_table *make_nocase_string_hash_table PARAMS ((int));
|
||||||
|
|
||||||
|
unsigned long hash_pointer PARAMS ((const void *));
|
||||||
|
|
||||||
|
/* From XEmacs, and hence from Dragon book. */
|
||||||
|
|
||||||
|
#define GOOD_HASH 65599 /* prime number just over 2^16; Dragon book, p. 435 */
|
||||||
|
#define HASH2(a,b) (GOOD_HASH * (a) + (b))
|
||||||
|
#define HASH3(a,b,c) (GOOD_HASH * HASH2 (a,b) + (c))
|
||||||
|
#define HASH4(a,b,c,d) (GOOD_HASH * HASH3 (a,b,c) + (d))
|
||||||
|
#define HASH5(a,b,c,d,e) (GOOD_HASH * HASH4 (a,b,c,d) + (e))
|
||||||
|
#define HASH6(a,b,c,d,e,f) (GOOD_HASH * HASH5 (a,b,c,d,e) + (f))
|
||||||
|
#define HASH7(a,b,c,d,e,f,g) (GOOD_HASH * HASH6 (a,b,c,d,e,f) + (g))
|
||||||
|
#define HASH8(a,b,c,d,e,f,g,h) (GOOD_HASH * HASH7 (a,b,c,d,e,f,g) + (h))
|
||||||
|
#define HASH9(a,b,c,d,e,f,g,h,i) (GOOD_HASH * HASH8 (a,b,c,d,e,f,g,h) + (i))
|
||||||
|
|
||||||
#endif /* HASH_H */
|
#endif /* HASH_H */
|
||||||
|
24
src/http.c
24
src/http.c
@ -84,7 +84,7 @@ extern int output_stream_regular;
|
|||||||
|
|
||||||
|
|
||||||
static int cookies_loaded_p;
|
static int cookies_loaded_p;
|
||||||
struct cookie_jar *wget_cookie_jar;
|
static struct cookie_jar *wget_cookie_jar;
|
||||||
|
|
||||||
#define TEXTHTML_S "text/html"
|
#define TEXTHTML_S "text/html"
|
||||||
#define TEXTXHTML_S "application/xhtml+xml"
|
#define TEXTXHTML_S "application/xhtml+xml"
|
||||||
@ -1349,14 +1349,23 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
look up conn->host in some cases. If that lookup failed, we
|
look up conn->host in some cases. If that lookup failed, we
|
||||||
don't need to bother with connect_to_host. */
|
don't need to bother with connect_to_host. */
|
||||||
if (host_lookup_failed)
|
if (host_lookup_failed)
|
||||||
|
{
|
||||||
|
request_free (req);
|
||||||
return HOSTERR;
|
return HOSTERR;
|
||||||
|
}
|
||||||
|
|
||||||
sock = connect_to_host (conn->host, conn->port);
|
sock = connect_to_host (conn->host, conn->port);
|
||||||
if (sock == E_HOST)
|
if (sock == E_HOST)
|
||||||
|
{
|
||||||
|
request_free (req);
|
||||||
return HOSTERR;
|
return HOSTERR;
|
||||||
|
}
|
||||||
else if (sock < 0)
|
else if (sock < 0)
|
||||||
|
{
|
||||||
|
request_free (req);
|
||||||
return (retryable_socket_connect_error (errno)
|
return (retryable_socket_connect_error (errno)
|
||||||
? CONERROR : CONIMPOSSIBLE);
|
? CONERROR : CONIMPOSSIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SSL
|
#ifdef HAVE_SSL
|
||||||
if (proxy && u->scheme == SCHEME_HTTPS)
|
if (proxy && u->scheme == SCHEME_HTTPS)
|
||||||
@ -1405,6 +1414,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
resp = resp_new (head);
|
resp = resp_new (head);
|
||||||
statcode = resp_status (resp, &message);
|
statcode = resp_status (resp, &message);
|
||||||
resp_free (resp);
|
resp_free (resp);
|
||||||
|
xfree (head);
|
||||||
if (statcode != 200)
|
if (statcode != 200)
|
||||||
{
|
{
|
||||||
failed_tunnel:
|
failed_tunnel:
|
||||||
@ -1582,6 +1592,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
hs->error = xstrdup (_("(no description)"));
|
hs->error = xstrdup (_("(no description)"));
|
||||||
else
|
else
|
||||||
hs->error = xstrdup (message);
|
hs->error = xstrdup (message);
|
||||||
|
xfree (message);
|
||||||
|
|
||||||
type = resp_header_strdup (resp, "Content-Type");
|
type = resp_header_strdup (resp, "Content-Type");
|
||||||
if (type)
|
if (type)
|
||||||
@ -1623,6 +1634,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
contrange = first_byte_pos;
|
contrange = first_byte_pos;
|
||||||
}
|
}
|
||||||
resp_free (resp);
|
resp_free (resp);
|
||||||
|
xfree (head);
|
||||||
|
|
||||||
/* 20x responses are counted among successful by default. */
|
/* 20x responses are counted among successful by default. */
|
||||||
if (H_20X (statcode))
|
if (H_20X (statcode))
|
||||||
@ -2832,7 +2844,17 @@ create_authorization_line (const char *au, const char *user,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
save_cookies (void)
|
||||||
|
{
|
||||||
|
if (wget_cookie_jar)
|
||||||
|
cookie_jar_save (wget_cookie_jar, opt.cookies_output);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
http_cleanup (void)
|
http_cleanup (void)
|
||||||
{
|
{
|
||||||
|
xfree_null (pconn.host);
|
||||||
|
if (wget_cookie_jar)
|
||||||
|
cookie_jar_delete (wget_cookie_jar);
|
||||||
}
|
}
|
||||||
|
12
src/init.c
12
src/init.c
@ -1,6 +1,5 @@
|
|||||||
/* Reading/parsing the initialization file.
|
/* Reading/parsing the initialization file.
|
||||||
Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2003, 2004
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||||
Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
This file is part of GNU Wget.
|
This file is part of GNU Wget.
|
||||||
|
|
||||||
@ -53,16 +52,14 @@ so, delete this exception statement from your version. */
|
|||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "netrc.h"
|
#include "netrc.h"
|
||||||
#include "cookies.h" /* for cookie_jar_delete */
|
|
||||||
#include "progress.h"
|
#include "progress.h"
|
||||||
#include "recur.h" /* for INFINITE_RECURSION */
|
#include "recur.h" /* for INFINITE_RECURSION */
|
||||||
|
#include "convert.h" /* for convert_cleanup */
|
||||||
|
|
||||||
#ifndef errno
|
#ifndef errno
|
||||||
extern int errno;
|
extern int errno;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct cookie_jar *wget_cookie_jar;
|
|
||||||
|
|
||||||
/* We want tilde expansion enabled only when reading `.wgetrc' lines;
|
/* We want tilde expansion enabled only when reading `.wgetrc' lines;
|
||||||
otherwise, it will be performed by the shell. This variable will
|
otherwise, it will be performed by the shell. This variable will
|
||||||
be set by the wgetrc-reading function. */
|
be set by the wgetrc-reading function. */
|
||||||
@ -1337,8 +1334,7 @@ cleanup (void)
|
|||||||
cleanup_html_url ();
|
cleanup_html_url ();
|
||||||
downloaded_files_free ();
|
downloaded_files_free ();
|
||||||
host_cleanup ();
|
host_cleanup ();
|
||||||
if (wget_cookie_jar)
|
log_cleanup ();
|
||||||
cookie_jar_delete (wget_cookie_jar);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
extern acc_t *netrc_list;
|
extern acc_t *netrc_list;
|
||||||
@ -1366,7 +1362,7 @@ cleanup (void)
|
|||||||
xfree_null (opt.referer);
|
xfree_null (opt.referer);
|
||||||
xfree_null (opt.http_user);
|
xfree_null (opt.http_user);
|
||||||
xfree_null (opt.http_passwd);
|
xfree_null (opt.http_passwd);
|
||||||
xfree_null (opt.user_header);
|
free_vec (opt.user_headers);
|
||||||
#ifdef HAVE_SSL
|
#ifdef HAVE_SSL
|
||||||
xfree_null (opt.sslcertkey);
|
xfree_null (opt.sslcertkey);
|
||||||
xfree_null (opt.sslcertfile);
|
xfree_null (opt.sslcertfile);
|
||||||
|
17
src/log.c
17
src/log.c
@ -1,5 +1,5 @@
|
|||||||
/* Messages logging.
|
/* Messages logging.
|
||||||
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GNU Wget.
|
This file is part of GNU Wget.
|
||||||
|
|
||||||
@ -684,11 +684,11 @@ struct ringel {
|
|||||||
char *buffer;
|
char *buffer;
|
||||||
int size;
|
int size;
|
||||||
};
|
};
|
||||||
|
static struct ringel ring[RING_SIZE]; /* ring data */
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
escnonprint_internal (const char *str, int for_uri)
|
escnonprint_internal (const char *str, int for_uri)
|
||||||
{
|
{
|
||||||
static struct ringel ring[RING_SIZE]; /* ring data */
|
|
||||||
static int ringpos; /* current ring position */
|
static int ringpos; /* current ring position */
|
||||||
|
|
||||||
int nprcnt = count_nonprint (str);
|
int nprcnt = count_nonprint (str);
|
||||||
@ -706,12 +706,15 @@ escnonprint_internal (const char *str, int for_uri)
|
|||||||
i.e. with three *additional* chars (two in URI-mode). Size
|
i.e. with three *additional* chars (two in URI-mode). Size
|
||||||
must also include the length of the original string and an
|
must also include the length of the original string and an
|
||||||
additional char for the terminating \0. */
|
additional char for the terminating \0. */
|
||||||
int needed_size = strlen (str) + 1 + for_uri ? (2 * nprcnt) : (3 * nprcnt);
|
int needed_size = strlen (str) + 1 + (for_uri ? 2 * nprcnt : 3 * nprcnt);
|
||||||
|
|
||||||
/* If the current buffer is uninitialized or too small,
|
/* If the current buffer is uninitialized or too small,
|
||||||
(re)allocate it. */
|
(re)allocate it. */
|
||||||
if (r->buffer == NULL || r->size < needed_size)
|
if (r->buffer == NULL || r->size < needed_size)
|
||||||
|
{
|
||||||
r->buffer = xrealloc (r->buffer, needed_size);
|
r->buffer = xrealloc (r->buffer, needed_size);
|
||||||
|
r->size = needed_size;
|
||||||
|
}
|
||||||
|
|
||||||
copy_and_escape (str, r->buffer, for_uri);
|
copy_and_escape (str, r->buffer, for_uri);
|
||||||
ringpos = (ringpos + 1) % RING_SIZE;
|
ringpos = (ringpos + 1) % RING_SIZE;
|
||||||
@ -748,6 +751,14 @@ escnonprint_uri (const char *str)
|
|||||||
{
|
{
|
||||||
return escnonprint_internal (str, 1);
|
return escnonprint_internal (str, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
log_cleanup (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < countof (ring); i++)
|
||||||
|
xfree_null (ring[i].buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/* When SIGHUP or SIGUSR1 are received, the output is redirected
|
/* When SIGHUP or SIGUSR1 are received, the output is redirected
|
||||||
elsewhere. Such redirection is only allowed once. */
|
elsewhere. Such redirection is only allowed once. */
|
||||||
|
@ -50,6 +50,7 @@ int log_set_save_context PARAMS ((int));
|
|||||||
|
|
||||||
void log_init PARAMS ((const char *, int));
|
void log_init PARAMS ((const char *, int));
|
||||||
void log_close PARAMS ((void));
|
void log_close PARAMS ((void));
|
||||||
|
void log_cleanup PARAMS ((void));
|
||||||
void log_request_redirect_output PARAMS ((const char *));
|
void log_request_redirect_output PARAMS ((const char *));
|
||||||
|
|
||||||
const char *escnonprint PARAMS ((const char *));
|
const char *escnonprint PARAMS ((const char *));
|
||||||
|
@ -61,7 +61,6 @@ extern int errno;
|
|||||||
#include "retr.h"
|
#include "retr.h"
|
||||||
#include "recur.h"
|
#include "recur.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "cookies.h"
|
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
#include "progress.h" /* for progress_handle_sigwinch */
|
#include "progress.h" /* for progress_handle_sigwinch */
|
||||||
#include "convert.h"
|
#include "convert.h"
|
||||||
@ -953,8 +952,8 @@ Can't timestamp and not clobber old files at the same time.\n"));
|
|||||||
legible (opt.quota));
|
legible (opt.quota));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.cookies_output && wget_cookie_jar)
|
if (opt.cookies_output)
|
||||||
cookie_jar_save (wget_cookie_jar, opt.cookies_output);
|
save_cookies ();
|
||||||
|
|
||||||
if (opt.convert_links && !opt.delete_after)
|
if (opt.convert_links && !opt.delete_after)
|
||||||
convert_all_links ();
|
convert_all_links ();
|
||||||
|
@ -214,8 +214,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
|||||||
data arrives slowly. */
|
data arrives slowly. */
|
||||||
int progress_interactive = 0;
|
int progress_interactive = 0;
|
||||||
|
|
||||||
/*int exact = flags & rb_read_exactly;*/
|
int exact = flags & rb_read_exactly;
|
||||||
int exact = 1;
|
|
||||||
wgint skip = 0;
|
wgint skip = 0;
|
||||||
|
|
||||||
/* How much data we've read/written. */
|
/* How much data we've read/written. */
|
||||||
|
@ -62,6 +62,7 @@ struct url;
|
|||||||
|
|
||||||
uerr_t http_loop PARAMS ((struct url *, char **, char **, const char *,
|
uerr_t http_loop PARAMS ((struct url *, char **, char **, const char *,
|
||||||
int *, struct url *));
|
int *, struct url *));
|
||||||
|
void save_cookies PARAMS ((void));
|
||||||
|
|
||||||
|
|
||||||
#endif /* RETR_H */
|
#endif /* RETR_H */
|
||||||
|
71
src/url.c
71
src/url.c
@ -1,6 +1,5 @@
|
|||||||
/* URL handling.
|
/* URL handling.
|
||||||
Copyright (C) 1995, 1996, 1997, 2000, 2001, 2003, 2003
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||||
Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
This file is part of GNU Wget.
|
This file is part of GNU Wget.
|
||||||
|
|
||||||
@ -1017,6 +1016,30 @@ url_full_path (const struct url *url)
|
|||||||
return full_path;
|
return full_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unescape CHR in an otherwise escaped STR. Used to selectively
|
||||||
|
escaping of certain characters, such as "/" and ":". Returns a
|
||||||
|
count of unescaped chars. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
unescape_single_char (char *str, char chr)
|
||||||
|
{
|
||||||
|
const char c1 = XNUM_TO_DIGIT (chr >> 4);
|
||||||
|
const char c2 = XNUM_TO_DIGIT (chr & 0xf);
|
||||||
|
char *h = str; /* hare */
|
||||||
|
char *t = str; /* tortoise */
|
||||||
|
for (; *h; h++, t++)
|
||||||
|
{
|
||||||
|
if (h[0] == '%' && h[1] == c1 && h[2] == c2)
|
||||||
|
{
|
||||||
|
*t = chr;
|
||||||
|
h += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*t = *h;
|
||||||
|
}
|
||||||
|
*t = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
/* Escape unsafe and reserved characters, except for the slash
|
/* Escape unsafe and reserved characters, except for the slash
|
||||||
characters. */
|
characters. */
|
||||||
|
|
||||||
@ -1024,28 +1047,10 @@ static char *
|
|||||||
url_escape_dir (const char *dir)
|
url_escape_dir (const char *dir)
|
||||||
{
|
{
|
||||||
char *newdir = url_escape_1 (dir, urlchr_unsafe | urlchr_reserved, 1);
|
char *newdir = url_escape_1 (dir, urlchr_unsafe | urlchr_reserved, 1);
|
||||||
char *h, *t;
|
|
||||||
if (newdir == dir)
|
if (newdir == dir)
|
||||||
return (char *)dir;
|
return (char *)dir;
|
||||||
|
|
||||||
/* Unescape slashes in NEWDIR. */
|
unescape_single_char (newdir, '/');
|
||||||
|
|
||||||
h = newdir; /* hare */
|
|
||||||
t = newdir; /* tortoise */
|
|
||||||
|
|
||||||
for (; *h; h++, t++)
|
|
||||||
{
|
|
||||||
/* url_escape_1 having converted '/' to "%2F" exactly. */
|
|
||||||
if (*h == '%' && h[1] == '2' && h[2] == 'F')
|
|
||||||
{
|
|
||||||
*t = '/';
|
|
||||||
h += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*t = *h;
|
|
||||||
}
|
|
||||||
*t = '\0';
|
|
||||||
|
|
||||||
return newdir;
|
return newdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1845,7 +1850,7 @@ url_string (const struct url *url, int hide_password)
|
|||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
char *result, *p;
|
char *result, *p;
|
||||||
char *quoted_user = NULL, *quoted_passwd = NULL;
|
char *quoted_host, *quoted_user = NULL, *quoted_passwd = NULL;
|
||||||
|
|
||||||
int scheme_port = supported_schemes[url->scheme].default_port;
|
int scheme_port = supported_schemes[url->scheme].default_port;
|
||||||
const char *scheme_str = supported_schemes[url->scheme].leading_string;
|
const char *scheme_str = supported_schemes[url->scheme].leading_string;
|
||||||
@ -1868,12 +1873,19 @@ url_string (const struct url *url, int hide_password)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Numeric IPv6 addresses can contain ':' and need to be quoted with
|
/* In the unlikely event that the host name contains non-printable
|
||||||
brackets. */
|
characters, quote it for displaying to the user. */
|
||||||
brackets_around_host = strchr (url->host, ':') != NULL;
|
quoted_host = url_escape_allow_passthrough (url->host);
|
||||||
|
|
||||||
|
/* Undo the quoting of colons that URL escaping performs. IPv6
|
||||||
|
addresses may legally contain colons, and in that case must be
|
||||||
|
placed in square brackets. */
|
||||||
|
if (quoted_host != url->host)
|
||||||
|
unescape_single_char (quoted_host, ':');
|
||||||
|
brackets_around_host = strchr (quoted_host, ':') != NULL;
|
||||||
|
|
||||||
size = (strlen (scheme_str)
|
size = (strlen (scheme_str)
|
||||||
+ strlen (url->host)
|
+ strlen (quoted_host)
|
||||||
+ (brackets_around_host ? 2 : 0)
|
+ (brackets_around_host ? 2 : 0)
|
||||||
+ fplen
|
+ fplen
|
||||||
+ 1);
|
+ 1);
|
||||||
@ -1902,7 +1914,7 @@ url_string (const struct url *url, int hide_password)
|
|||||||
|
|
||||||
if (brackets_around_host)
|
if (brackets_around_host)
|
||||||
*p++ = '[';
|
*p++ = '[';
|
||||||
APPEND (p, url->host);
|
APPEND (p, quoted_host);
|
||||||
if (brackets_around_host)
|
if (brackets_around_host)
|
||||||
*p++ = ']';
|
*p++ = ']';
|
||||||
if (url->port != scheme_port)
|
if (url->port != scheme_port)
|
||||||
@ -1919,9 +1931,10 @@ url_string (const struct url *url, int hide_password)
|
|||||||
|
|
||||||
if (quoted_user && quoted_user != url->user)
|
if (quoted_user && quoted_user != url->user)
|
||||||
xfree (quoted_user);
|
xfree (quoted_user);
|
||||||
if (quoted_passwd && !hide_password
|
if (quoted_passwd && !hide_password && quoted_passwd != url->passwd)
|
||||||
&& quoted_passwd != url->passwd)
|
|
||||||
xfree (quoted_passwd);
|
xfree (quoted_passwd);
|
||||||
|
if (quoted_host != url->host)
|
||||||
|
xfree (quoted_host);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -558,6 +558,14 @@ fopen_excl (const char *fname, int binary)
|
|||||||
return NULL;
|
return NULL;
|
||||||
return fdopen (fd, binary ? "wb" : "w");
|
return fdopen (fd, binary ? "wb" : "w");
|
||||||
#else /* not O_EXCL */
|
#else /* not O_EXCL */
|
||||||
|
/* Manually check whether the file exists. This is prone to race
|
||||||
|
conditions, but systems without O_EXCL haven't deserved
|
||||||
|
better. */
|
||||||
|
if (file_exists_p (fname))
|
||||||
|
{
|
||||||
|
errno = EEXIST;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return fopen (fname, binary ? "wb" : "w");
|
return fopen (fname, binary ? "wb" : "w");
|
||||||
#endif /* not O_EXCL */
|
#endif /* not O_EXCL */
|
||||||
}
|
}
|
||||||
|
200
src/xmalloc.c
200
src/xmalloc.c
@ -1,5 +1,5 @@
|
|||||||
/* Wrappers around malloc and memory debugging support.
|
/* Wrappers around malloc and memory debugging support.
|
||||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GNU Wget.
|
This file is part of GNU Wget.
|
||||||
|
|
||||||
@ -42,6 +42,7 @@ so, delete this exception statement from your version. */
|
|||||||
|
|
||||||
#include "wget.h"
|
#include "wget.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
#include "hash.h" /* for hash_pointer */
|
||||||
|
|
||||||
#ifndef errno
|
#ifndef errno
|
||||||
extern int errno;
|
extern int errno;
|
||||||
@ -79,11 +80,11 @@ memfatal (const char *context, long attempted_size)
|
|||||||
|
|
||||||
If memory debugging is not turned on, xmalloc.h defines these:
|
If memory debugging is not turned on, xmalloc.h defines these:
|
||||||
|
|
||||||
#define xmalloc xmalloc_real
|
#define xmalloc checking_malloc
|
||||||
#define xmalloc0 xmalloc0_real
|
#define xmalloc0 checking_malloc0
|
||||||
#define xrealloc xrealloc_real
|
#define xrealloc checking_realloc
|
||||||
#define xstrdup xstrdup_real
|
#define xstrdup checking_strdup
|
||||||
#define xfree xfree_real
|
#define xfree checking_free
|
||||||
|
|
||||||
In case of memory debugging, the definitions are a bit more
|
In case of memory debugging, the definitions are a bit more
|
||||||
complex, because we want to provide more information, *and* we want
|
complex, because we want to provide more information, *and* we want
|
||||||
@ -91,13 +92,14 @@ memfatal (const char *context, long attempted_size)
|
|||||||
and friends need to be macros in the first place.) Then it looks
|
and friends need to be macros in the first place.) Then it looks
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
#define xmalloc(a) xmalloc_debug (a, __FILE__, __LINE__)
|
#define xmalloc(a) debugging_malloc (a, __FILE__, __LINE__)
|
||||||
#define xmalloc0(a) xmalloc0_debug (a, __FILE__, __LINE__)
|
#define xmalloc0(a) debugging_malloc0 (a, __FILE__, __LINE__)
|
||||||
#define xrealloc(a, b) xrealloc_debug (a, b, __FILE__, __LINE__)
|
#define xrealloc(a, b) debugging_realloc (a, b, __FILE__, __LINE__)
|
||||||
#define xstrdup(a) xstrdup_debug (a, __FILE__, __LINE__)
|
#define xstrdup(a) debugging_strdup (a, __FILE__, __LINE__)
|
||||||
#define xfree(a) xfree_debug (a, __FILE__, __LINE__)
|
#define xfree(a) debugging_free (a, __FILE__, __LINE__)
|
||||||
|
|
||||||
Each of the *_debug function does its magic and calls the real one. */
|
Each of the debugging_* functions does its magic and calls the
|
||||||
|
corresponding checking_* one. */
|
||||||
|
|
||||||
#ifdef DEBUG_MALLOC
|
#ifdef DEBUG_MALLOC
|
||||||
# define STATIC_IF_DEBUG static
|
# define STATIC_IF_DEBUG static
|
||||||
@ -106,7 +108,7 @@ memfatal (const char *context, long attempted_size)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC_IF_DEBUG void *
|
STATIC_IF_DEBUG void *
|
||||||
xmalloc_real (size_t size)
|
checking_malloc (size_t size)
|
||||||
{
|
{
|
||||||
void *ptr = malloc (size);
|
void *ptr = malloc (size);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
@ -115,7 +117,7 @@ xmalloc_real (size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC_IF_DEBUG void *
|
STATIC_IF_DEBUG void *
|
||||||
xmalloc0_real (size_t size)
|
checking_malloc0 (size_t size)
|
||||||
{
|
{
|
||||||
/* Using calloc can be faster than malloc+memset because some calloc
|
/* Using calloc can be faster than malloc+memset because some calloc
|
||||||
implementations know when they're dealing with zeroed-out memory
|
implementations know when they're dealing with zeroed-out memory
|
||||||
@ -127,7 +129,7 @@ xmalloc0_real (size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC_IF_DEBUG void *
|
STATIC_IF_DEBUG void *
|
||||||
xrealloc_real (void *ptr, size_t newsize)
|
checking_realloc (void *ptr, size_t newsize)
|
||||||
{
|
{
|
||||||
void *newptr;
|
void *newptr;
|
||||||
|
|
||||||
@ -144,7 +146,7 @@ xrealloc_real (void *ptr, size_t newsize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC_IF_DEBUG char *
|
STATIC_IF_DEBUG char *
|
||||||
xstrdup_real (const char *s)
|
checking_strdup (const char *s)
|
||||||
{
|
{
|
||||||
char *copy;
|
char *copy;
|
||||||
|
|
||||||
@ -164,31 +166,31 @@ xstrdup_real (const char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC_IF_DEBUG void
|
STATIC_IF_DEBUG void
|
||||||
xfree_real (void *ptr)
|
checking_free (void *ptr)
|
||||||
{
|
{
|
||||||
/* Wget's xfree() must not be passed a NULL pointer. This is for
|
/* Wget's xfree() must not be passed a NULL pointer. This is for
|
||||||
historical reasons: many pre-C89 systems were known to bomb at
|
historical reasons: pre-C89 systems were reported to bomb at
|
||||||
free(NULL), and Wget was careful to use xfree_null when there is
|
free(NULL), and Wget was careful to not call xfree when there was
|
||||||
a possibility of PTR being NULL. (It might have been better to
|
a possibility of PTR being NULL. (It might have been better to
|
||||||
simply have xfree() do nothing if ptr==NULL.)
|
simply have xfree() do nothing if ptr==NULL.)
|
||||||
|
|
||||||
Since the code is already written that way, this assert simply
|
Since the code is already written that way, this assert simply
|
||||||
enforces that constraint. Code that thinks it doesn't deal with
|
enforces the existing constraint. The benefit is double-checking
|
||||||
NULL, and it in fact does, aborts immediately. If you trip on
|
the logic: code that thinks it can't be passed a NULL pointer,
|
||||||
this, either the code has a pointer handling bug or should have
|
while it in fact can, aborts here. If you trip on this, either
|
||||||
called xfree_null instead of xfree. Correctly written code
|
the code has a pointer handling bug or should have called
|
||||||
should never trigger this assertion.
|
xfree_null instead of xfree. Correctly written code should never
|
||||||
|
trigger this assertion.
|
||||||
|
|
||||||
If the assertion proves to be too much of a hassle, it can be
|
The downside is that the uninitiated might not expect xfree(NULL)
|
||||||
removed and a check that makes NULL a no-op placed in its stead.
|
to abort. If the assertion proves to be too much of a hassle, it
|
||||||
If that is done, xfree_null is no longer needed and should be
|
can be removed and a check that makes NULL a no-op placed in its
|
||||||
removed. */
|
stead. If that is done, xfree_null is no longer needed and
|
||||||
|
should be removed. */
|
||||||
assert (ptr != NULL);
|
assert (ptr != NULL);
|
||||||
|
|
||||||
free (ptr);
|
free (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* xfree_real is unnecessary because free doesn't require any special
|
|
||||||
functionality. */
|
|
||||||
|
|
||||||
#ifdef DEBUG_MALLOC
|
#ifdef DEBUG_MALLOC
|
||||||
|
|
||||||
@ -202,8 +204,10 @@ xfree_real (void *ptr)
|
|||||||
* Making malloc store its entry into a simple array and free remove
|
* Making malloc store its entry into a simple array and free remove
|
||||||
stuff from that array. At the end, print the pointers which have
|
stuff from that array. At the end, print the pointers which have
|
||||||
not been freed, along with the source file and the line number.
|
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.
|
* Checking for "invalid frees", where free is called on a pointer
|
||||||
|
not obtained with malloc, or where the same pointer is freed
|
||||||
|
twice.
|
||||||
|
|
||||||
Note that this kind of memory leak checking strongly depends on
|
Note that this kind of memory leak checking strongly depends on
|
||||||
every malloc() being followed by a free(), even if the program is
|
every malloc() being followed by a free(), even if the program is
|
||||||
@ -212,58 +216,82 @@ xfree_real (void *ptr)
|
|||||||
|
|
||||||
static int malloc_count, free_count;
|
static int malloc_count, free_count;
|
||||||
|
|
||||||
|
/* Home-grown hash table of mallocs: */
|
||||||
|
|
||||||
|
#define SZ 100003 /* Prime number a little over 100,000.
|
||||||
|
Increase the table size if you need
|
||||||
|
to debug larger Wget runs. */
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
char *ptr;
|
const void *ptr;
|
||||||
const char *file;
|
const char *file;
|
||||||
int line;
|
int line;
|
||||||
} malloc_debug[100000];
|
} malloc_table[SZ];
|
||||||
|
|
||||||
/* Both register_ptr and unregister_ptr take O(n) operations to run,
|
/* Find PTR's position in malloc_table. If PTR is not found, return
|
||||||
which can be a real problem. It would be nice to use a hash table
|
the next available position. */
|
||||||
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
|
static inline int
|
||||||
|
ptr_position (const void *ptr)
|
||||||
|
{
|
||||||
|
int i = hash_pointer (ptr) % SZ;
|
||||||
|
for (; malloc_table[i].ptr != NULL; i = (i + 1) % SZ)
|
||||||
|
if (malloc_table[i].ptr == ptr)
|
||||||
|
return i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register PTR in malloc_table. Abort if this is not possible
|
||||||
(presumably due to the number of current allocations exceeding the
|
(presumably due to the number of current allocations exceeding the
|
||||||
size of malloc_debug.) */
|
size of malloc_table.) */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
register_ptr (void *ptr, const char *file, int line)
|
register_ptr (const void *ptr, const char *file, int line)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < countof (malloc_debug); i++)
|
if (malloc_count - free_count > SZ)
|
||||||
if (malloc_debug[i].ptr == NULL)
|
|
||||||
{
|
|
||||||
malloc_debug[i].ptr = ptr;
|
|
||||||
malloc_debug[i].file = file;
|
|
||||||
malloc_debug[i].line = line;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
|
i = ptr_position (ptr);
|
||||||
|
malloc_table[i].ptr = ptr;
|
||||||
|
malloc_table[i].file = file;
|
||||||
|
malloc_table[i].line = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unregister PTR from malloc_debug. Abort if PTR is not present in
|
/* Unregister PTR from malloc_table. Return 0 if PTR is not present
|
||||||
malloc_debug. (This catches calling free() with a bogus pointer.) */
|
in malloc_table. */
|
||||||
|
|
||||||
static void
|
static int
|
||||||
unregister_ptr (void *ptr)
|
unregister_ptr (void *ptr)
|
||||||
{
|
{
|
||||||
int i;
|
int i = ptr_position (ptr);
|
||||||
for (i = 0; i < countof (malloc_debug); i++)
|
if (malloc_table[i].ptr == NULL)
|
||||||
if (malloc_debug[i].ptr == ptr)
|
return 0;
|
||||||
|
malloc_table[i].ptr = NULL;
|
||||||
|
|
||||||
|
/* Relocate malloc_table entries immediately following PTR. */
|
||||||
|
for (i = (i + 1) % SZ; malloc_table[i].ptr != NULL; i = (i + 1) % SZ)
|
||||||
{
|
{
|
||||||
malloc_debug[i].ptr = NULL;
|
const void *ptr2 = malloc_table[i].ptr;
|
||||||
return;
|
/* Find the new location for the key. */
|
||||||
|
int j = hash_pointer (ptr2) % SZ;
|
||||||
|
for (; malloc_table[j].ptr != NULL; j = (j + 1) % SZ)
|
||||||
|
if (ptr2 == malloc_table[j].ptr)
|
||||||
|
/* No need to relocate entry at [i]; it's already at or near
|
||||||
|
its hash position. */
|
||||||
|
goto cont_outer;
|
||||||
|
malloc_table[j] = malloc_table[i];
|
||||||
|
malloc_table[i].ptr = NULL;
|
||||||
|
cont_outer:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
abort ();
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the malloc debug stats that can be gathered from the above
|
/* Print the malloc debug stats gathered from the above information.
|
||||||
information. Currently this is the count of mallocs, frees, the
|
Currently this is the count of mallocs, frees, the difference
|
||||||
difference between the two, and the dump of the contents of
|
between the two, and the dump of the contents of malloc_table. The
|
||||||
malloc_debug. The last part are the memory leaks. */
|
last part are the memory leaks. */
|
||||||
|
|
||||||
void
|
void
|
||||||
print_malloc_debug_stats (void)
|
print_malloc_debug_stats (void)
|
||||||
@ -271,34 +299,35 @@ print_malloc_debug_stats (void)
|
|||||||
int i;
|
int i;
|
||||||
printf ("\nMalloc: %d\nFree: %d\nBalance: %d\n\n",
|
printf ("\nMalloc: %d\nFree: %d\nBalance: %d\n\n",
|
||||||
malloc_count, free_count, malloc_count - free_count);
|
malloc_count, free_count, malloc_count - free_count);
|
||||||
for (i = 0; i < countof (malloc_debug); i++)
|
for (i = 0; i < SZ; i++)
|
||||||
if (malloc_debug[i].ptr != NULL)
|
if (malloc_table[i].ptr != NULL)
|
||||||
printf ("0x%08ld: %s:%d\n", (long)malloc_debug[i].ptr,
|
printf ("0x%0*lx: %s:%d\n", 2 * sizeof (void *),
|
||||||
malloc_debug[i].file, malloc_debug[i].line);
|
(long) malloc_table[i].ptr,
|
||||||
|
malloc_table[i].file, malloc_table[i].line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
xmalloc_debug (size_t size, const char *source_file, int source_line)
|
debugging_malloc (size_t size, const char *source_file, int source_line)
|
||||||
{
|
{
|
||||||
void *ptr = xmalloc_real (size);
|
void *ptr = checking_malloc (size);
|
||||||
++malloc_count;
|
++malloc_count;
|
||||||
register_ptr (ptr, source_file, source_line);
|
register_ptr (ptr, source_file, source_line);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
xmalloc0_debug (size_t size, const char *source_file, int source_line)
|
debugging_malloc0 (size_t size, const char *source_file, int source_line)
|
||||||
{
|
{
|
||||||
void *ptr = xmalloc0_real (size);
|
void *ptr = checking_malloc0 (size);
|
||||||
++malloc_count;
|
++malloc_count;
|
||||||
register_ptr (ptr, source_file, source_line);
|
register_ptr (ptr, source_file, source_line);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
xrealloc_debug (void *ptr, size_t newsize, const char *source_file, int source_line)
|
debugging_realloc (void *ptr, size_t newsize, const char *source_file, int source_line)
|
||||||
{
|
{
|
||||||
void *newptr = xrealloc_real (ptr, newsize);
|
void *newptr = checking_realloc (ptr, newsize);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
++malloc_count;
|
++malloc_count;
|
||||||
@ -313,29 +342,36 @@ xrealloc_debug (void *ptr, size_t newsize, const char *source_file, int source_l
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
xstrdup_debug (const char *s, const char *source_file, int source_line)
|
debugging_strdup (const char *s, const char *source_file, int source_line)
|
||||||
{
|
{
|
||||||
char *copy = xstrdup_real (s);
|
char *copy = checking_strdup (s);
|
||||||
++malloc_count;
|
++malloc_count;
|
||||||
register_ptr (copy, source_file, source_line);
|
register_ptr (copy, source_file, source_line);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xfree_debug (void *ptr, const char *source_file, int source_line)
|
debugging_free (void *ptr, const char *source_file, int source_line)
|
||||||
{
|
{
|
||||||
/* See xfree_real for rationale of this abort. We repeat it here
|
/* See checking_free for rationale of this abort. We repeat it here
|
||||||
because we can print the file and the line where the offending
|
because we can print the file and the line where the offending
|
||||||
free occurred. */
|
free occurred. */
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
{
|
{
|
||||||
fprintf ("%s: xfree(NULL) at %s:%d\n",
|
fprintf (stderr, "%s: xfree(NULL) at %s:%d\n",
|
||||||
exec_name, source_file, source_line);
|
exec_name, source_file, source_line);
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
if (!unregister_ptr (ptr))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s: bad xfree(%0*lx) at %s:%d\n",
|
||||||
|
exec_name, 2 * sizeof (void *), (long) ptr,
|
||||||
|
source_file, source_line);
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
++free_count;
|
++free_count;
|
||||||
unregister_ptr (ptr);
|
|
||||||
xfree_real (ptr);
|
checking_free (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* DEBUG_MALLOC */
|
#endif /* DEBUG_MALLOC */
|
||||||
|
@ -30,46 +30,50 @@ so, delete this exception statement from your version. */
|
|||||||
#ifndef XMALLOC_H
|
#ifndef XMALLOC_H
|
||||||
#define XMALLOC_H
|
#define XMALLOC_H
|
||||||
|
|
||||||
/* Define this if you want primitive but extensive malloc debugging.
|
/* Define this to get Wget's builtin malloc debugging, which is
|
||||||
It will make Wget extremely slow, so only do it in development
|
primitive but fairly extensive. It will make Wget somewhat slower
|
||||||
builds. */
|
and larger, so it should be used by developers only. */
|
||||||
#undef DEBUG_MALLOC
|
#undef DEBUG_MALLOC
|
||||||
|
|
||||||
/* When DEBUG_MALLOC is not defined (which is normally the case), the
|
/* When DEBUG_MALLOC is not defined (which is normally the case), the
|
||||||
allocation functions directly map to *_real wrappers. In the
|
allocator identifiers are mapped to checking_* wrappers, which exit
|
||||||
DEBUG_MALLOC mode, they also record the file and line where the
|
Wget if malloc/realloc/strdup return NULL
|
||||||
offending malloc/free/... was invoked.
|
|
||||||
|
|
||||||
*Note*: xfree(NULL) aborts. If the pointer you're freeing can be
|
In DEBUG_MALLOC mode, the allocators are mapped to debugging_*
|
||||||
NULL, use xfree_null instead. */
|
wrappers, which also record the file and line from which the
|
||||||
|
allocation was attempted. At the end of the program, a detailed
|
||||||
|
summary of unfreed allocations is displayed.
|
||||||
|
|
||||||
|
*Note*: xfree(NULL) aborts in both modes. If the pointer you're
|
||||||
|
freeing can be NULL, use xfree_null instead. */
|
||||||
|
|
||||||
#ifndef DEBUG_MALLOC
|
#ifndef DEBUG_MALLOC
|
||||||
|
|
||||||
#define xmalloc xmalloc_real
|
#define xmalloc checking_malloc
|
||||||
#define xmalloc0 xmalloc0_real
|
#define xmalloc0 checking_malloc0
|
||||||
#define xrealloc xrealloc_real
|
#define xrealloc checking_realloc
|
||||||
#define xstrdup xstrdup_real
|
#define xstrdup checking_strdup
|
||||||
#define xfree xfree_real
|
#define xfree checking_free
|
||||||
|
|
||||||
void *xmalloc_real PARAMS ((size_t));
|
void *checking_malloc PARAMS ((size_t));
|
||||||
void *xmalloc0_real PARAMS ((size_t));
|
void *checking_malloc0 PARAMS ((size_t));
|
||||||
void *xrealloc_real PARAMS ((void *, size_t));
|
void *checking_realloc PARAMS ((void *, size_t));
|
||||||
char *xstrdup_real PARAMS ((const char *));
|
char *checking_strdup PARAMS ((const char *));
|
||||||
void xfree_real PARAMS ((void *));
|
void checking_free PARAMS ((void *));
|
||||||
|
|
||||||
#else /* DEBUG_MALLOC */
|
#else /* DEBUG_MALLOC */
|
||||||
|
|
||||||
#define xmalloc(s) xmalloc_debug (s, __FILE__, __LINE__)
|
#define xmalloc(s) debugging_malloc (s, __FILE__, __LINE__)
|
||||||
#define xmalloc0(s) xmalloc0_debug (s, __FILE__, __LINE__)
|
#define xmalloc0(s) debugging_malloc0 (s, __FILE__, __LINE__)
|
||||||
#define xrealloc(p, s) xrealloc_debug (p, s, __FILE__, __LINE__)
|
#define xrealloc(p, s) debugging_realloc (p, s, __FILE__, __LINE__)
|
||||||
#define xstrdup(p) xstrdup_debug (p, __FILE__, __LINE__)
|
#define xstrdup(p) debugging_strdup (p, __FILE__, __LINE__)
|
||||||
#define xfree(p) xfree_debug (p, __FILE__, __LINE__)
|
#define xfree(p) debugging_free (p, __FILE__, __LINE__)
|
||||||
|
|
||||||
void *xmalloc_debug PARAMS ((size_t, const char *, int));
|
void *debugging_malloc PARAMS ((size_t, const char *, int));
|
||||||
void *xmalloc0_debug PARAMS ((size_t, const char *, int));
|
void *debugging_malloc0 PARAMS ((size_t, const char *, int));
|
||||||
void *xrealloc_debug PARAMS ((void *, size_t, const char *, int));
|
void *debugging_realloc PARAMS ((void *, size_t, const char *, int));
|
||||||
char *xstrdup_debug PARAMS ((const char *, const char *, int));
|
char *debugging_strdup PARAMS ((const char *, const char *, int));
|
||||||
void xfree_debug PARAMS ((void *, const char *, int));
|
void debugging_free PARAMS ((void *, const char *, int));
|
||||||
|
|
||||||
#endif /* DEBUG_MALLOC */
|
#endif /* DEBUG_MALLOC */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user