httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject [PATCH] using freed memory, and a memory debugger
Date Wed, 08 Oct 1997 09:09:29 GMT
Here's a patch which adds ALLOC_DEBUG, a feature which can assist finding
memory problems such as using the wrong pool, or using an already cleared
pool, or whatnot.  It's not anywhere near perfect, but it's better than
nothing. 

And it found one bug already.  main() called clear_pool(pconf) before
calling standalone_main... and standalone_main assumed the pool still had
some things in it (for the listeners).  There's no need to clear it,
standalone_main will do it shortly thereafter. 

While looking at that I noticed that we kill cleanups on the scoreboard
file (if using a file) even before it's opened the first time around. 

Both those fixes are included. 

Can the segfault folks give this a whirl and see what you get? 

-- 
Dean Gaudet, Performance Analyst, Transmeta Corp.

Index: main/alloc.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/alloc.c,v
retrieving revision 1.49
diff -u -r1.49 alloc.c
--- alloc.c	1997/10/05 02:06:36	1.49
+++ alloc.c	1997/10/08 08:37:28
@@ -63,6 +63,20 @@
 
 #include <stdarg.h>
 
+/* debugging support, define this to enable code which helps detect re-use
+ * of freed memory and other such nonsense.
+ *
+ * The theory is simple.  The FILL_BYTE (0xa5) is written over all malloc'd
+ * memory as we receive it, and is written over everything that we free up
+ * during a clear_pool.  We check that blocks on the free list always
+ * have the FILL_BYTE in them, and we check during palloc() that the bytes
+ * still have FILL_BYTE in them.  If you ever see garbage URLs or whatnot
+ * containing lots of 0xa5s then you know something used data that's been
+ * freed.
+ */
+/* #define ALLOC_DEBUG */
+
+
 /*****************************************************************
  *
  * Managing free storage blocks...
@@ -98,6 +112,28 @@
 mutex *alloc_mutex = NULL;
 mutex *spawn_mutex = NULL;
 
+#ifdef ALLOC_DEBUG
+#define FILL_BYTE	((char)(0xa5))
+
+#define debug_fill(ptr,size)	((void)memset((ptr), FILL_BYTE, (size)))
+
+static ap_inline void debug_verify_filled(const char *ptr,
+    const char *endp, const char *error_msg)
+{
+    for (; ptr < endp; ++ptr) {
+	if (*ptr != FILL_BYTE) {
+	    fputs(error_msg, stderr);
+	    abort();
+	    exit(1);
+	}
+    }
+}
+
+#else
+#define debug_fill(a,b)
+#define debug_verify_filled(a,b,c)
+#endif
+
 
 /* Get a completely new block from the system pool. Note that we rely on
    malloc() to provide aligned memory. */
@@ -111,6 +147,7 @@
 	fprintf(stderr, "Ouch!  malloc failed in malloc_block()\n");
 	exit(1);
     }
+    debug_fill(blok, size + sizeof(union block_hdr));
     blok->h.next = NULL;
     blok->h.first_avail = (char *) (blok + 1);
     blok->h.endp = size + blok->h.first_avail;
@@ -161,11 +198,13 @@
     while (blok->h.next != NULL) {
 	chk_on_blk_list(blok, old_free_list);
 	blok->h.first_avail = (char *) (blok + 1);
+	debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
 	blok = blok->h.next;
     }
 
     chk_on_blk_list(blok, old_free_list);
     blok->h.first_avail = (char *) (blok + 1);
+    debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
 
     /* Finally, reset next pointer to get the old free blocks back */
 
@@ -174,8 +213,6 @@
 }
 
 
-
-
 /* Get a new block, from our own free list if possible, from the system
  * if necessary.  Must be called with alarms blocked.
  */
@@ -193,6 +230,8 @@
 	if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) {
 	    *lastptr = blok->h.next;
 	    blok->h.next = NULL;
+	    debug_verify_filled(blok->h.first_avail, blok->h.endp,
+		"Ouch!  Someone trounced a block on the free list!\n");
 	    return blok;
 	}
 	else {
@@ -204,11 +243,13 @@
     /* Nope. */
 
     min_size += BLOCK_MINFREE;
-    return malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC);
+    blok = malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC);
+    debug_verify_filled(blok->h.first_avail, blok->h.endp,
+	"Ouch!  Someone trounced a block on the free list!\n");
+    return blok;
 }
 
 
-
 /* Accounting */
 
 long bytes_in_block_list(union block_hdr *blok)
@@ -318,6 +359,8 @@
 
     a->last = a->first;
     a->first->h.first_avail = a->free_first_avail;
+    debug_fill(a->first->h.first_avail,
+	a->first->h.endp - a->first->h.first_avail);
 
     unblock_alarms();
 }
@@ -377,6 +420,8 @@
     new_first_avail = first_avail + size;
 
     if (new_first_avail <= blok->h.endp) {
+	debug_verify_filled(first_avail, blok->h.endp,
+	    "Ouch!  Someone trounced past the end of their allocation!\n");
 	blok->h.first_avail = new_first_avail;
 	return (void *) first_avail;
     }
Index: main/http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
retrieving revision 1.234
diff -u -r1.234 http_main.c
--- http_main.c	1997/10/07 19:34:01	1.234
+++ http_main.c	1997/10/08 08:37:29
@@ -1406,7 +1406,7 @@
 #else
 #define SCOREBOARD_FILE
 static scoreboard _scoreboard_image;
-static int scoreboard_fd;
+static int scoreboard_fd = -1;
 
 /* XXX: things are seriously screwed if we ever have to do a partial
  * read or write ... we could get a corrupted scoreboard
@@ -3122,7 +3122,7 @@
 	    restart_time = time(NULL);
 	}
 #ifdef SCOREBOARD_FILE
-	else {
+	else if (scoreboard_fd != -1) {
 	    kill_cleanups_for_fd(pconf, scoreboard_fd);
 	}
 #endif
@@ -3392,7 +3392,6 @@
     init_modules(pconf, server_conf);
 
     if (standalone) {
-	clear_pool(pconf);	/* standalone_main rereads... */
 	STANDALONE_MAIN(argc, argv);
     }
     else {


Mime
View raw message