]> sjero.net Git - wget/blobdiff - src/xmalloc.c
[svn] Abort on xfree(NULL).
[wget] / src / xmalloc.c
index 3464cbfe133fe7e431ced9084aac1dd19d7d618e..311506ec19faf68a72959624665670377d1cd1a1 100644 (file)
@@ -56,19 +56,20 @@ extern int errno;
 
    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);
 }
 
@@ -76,13 +77,13 @@ memfatal (const char *context, long size)
    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
@@ -92,9 +93,9 @@ memfatal (const char *context, long size)
 
      #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.  */
 
@@ -162,6 +163,33 @@ xstrdup_real (const char *s)
   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
@@ -296,10 +324,18 @@ xstrdup_debug (const char *s, const char *source_file, int source_line)
 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 */