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. */
+ interface that checks for memory leaks. */
/* Croak the fatal memory error and bail out with non-zero exit
status. */
static void
-memfatal (const char *context, long size)
+memfatal (const char *context, long attempted_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);
+ logprintf (LOG_ALWAYS,
+ _("%s: %s: Failed to allocate %ld bytes; memory exhausted.\n"),
+ exec_name, context, attempted_size);
exit (1);
}
distinguished from the debugging functions, and from the macros.
Explanation follows:
- If memory debugging is not turned on, wget.h defines these:
+ If memory debugging is not turned on, xmalloc.h defines these:
#define xmalloc xmalloc_real
#define xmalloc0 xmalloc0_real
#define xrealloc xrealloc_real
#define xstrdup xstrdup_real
- #define xfree free
+ #define xfree xfree_real
In case of memory debugging, the definitions are a bit more
complex, because we want to provide more information, *and* we want
#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__)
+ #define xfree(a) xfree_debug (a, __FILE__, __LINE__)
Each of the *_debug function does its magic and calls the real one. */
return copy;
}
+STATIC_IF_DEBUG void
+xfree_real (void *ptr)
+{
+ /* Wget's xfree() must not be passed a NULL pointer. This is for
+ historical reasons: many pre-C89 systems were known to bomb at
+ free(NULL), and Wget was careful to use xfree_null when there is
+ a possibility of PTR being NULL. (It might have been better to
+ simply have xfree() do nothing if ptr==NULL.)
+
+ Since the code is already written that way, this assert simply
+ enforces that constraint. Code that thinks it doesn't deal with
+ NULL, and it in fact does, aborts immediately. If you trip on
+ this, either the code has a pointer handling bug or should have
+ called 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
+ removed and a check that makes NULL a no-op placed in its stead.
+ If that is done, xfree_null is no longer needed and should be
+ removed. */
+ assert (ptr != NULL);
+ free (ptr);
+}
+
+/* xfree_real is unnecessary because free doesn't require any special
+ functionality. */
+\f
#ifdef DEBUG_MALLOC
/* Crude home-grown routines for debugging some malloc-related
void
xfree_debug (void *ptr, const char *source_file, int source_line)
{
- assert (ptr != NULL);
+ /* See xfree_real for rationale of this abort. We repeat it here
+ because we can print the file and the line where the offending
+ free occurred. */
+ if (ptr == NULL)
+ {
+ fprintf ("%s: xfree(NULL) at %s:%d\n",
+ exec_name, source_file, source_line);
+ abort ();
+ }
++free_count;
unregister_ptr (ptr);
- free (ptr);
+ xfree_real (ptr);
}
#endif /* DEBUG_MALLOC */