httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject RE: [PATCH] using freed memory, and a memory debugger
Date Thu, 09 Oct 1997 21:46:05 GMT
Yup they're against 1.3b1.  Patch it in, add -DALLOC_USE_MALLOC to
EXTRA_CFLAGS, and then try out various things: 

- try accessing a non-existant url
- try accessing /server-status
- try accessing a plain html page or gifs or anything static
- try accessing a parsed html page
- try accessing an automatic directory index
- try kill -USR1, -HUP, and -TERM

Tell us if you find anything.  I've included the latest version of the
patch.  You'll need this because it fixes two problems that purify would
barf on, and has the ALLOC_USE_MALLOC code which makes purifying more
relevant. 

-- 
Dean Gaudet, Performance Analyst, Transmeta Corp.

On Thu, 9 Oct 1997, Charles Randall wrote:

> I've got Purify, can these patches be applied to 1.3b1? What is the test
> case?

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 23:32:55
@@ -63,6 +63,34 @@
 
 #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 */
+
+/* debugging support, if defined all allocations will be done with
+ * malloc and free()d appropriately at the end.  This is intended to be
+ * used with something like Electric Fence or Purify to help detect
+ * memory problems.
+ */
+/* #define ALLOC_USE_MALLOC */
+
+#ifdef ALLOC_USE_MALLOC
+#undef BLOCK_MINFREE
+#undef BLOCK_MINALLOC
+#define BLOCK_MINFREE	0
+#define BLOCK_MINALLOC	0
+#endif
+
+
 /*****************************************************************
  *
  * Managing free storage blocks...
@@ -98,6 +126,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 +161,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;
@@ -138,6 +189,14 @@
 
 void free_blocks(union block_hdr *blok)
 {
+#ifdef ALLOC_USE_MALLOC
+    union block_hdr *next;
+
+    for (; blok; blok = next) {
+	next = blok->h.next;
+	free(blok);
+    }
+#else
     /* First, put new blocks at the head of the free list ---
      * we'll eventually bash the 'next' pointer of the last block
      * in the chain to point to the free blocks we already had.
@@ -161,21 +220,22 @@
     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 */
 
     blok->h.next = old_free_list;
     (void) release_mutex(alloc_mutex);
+#endif
 }
 
 
-
-
 /* Get a new block, from our own free list if possible, from the system
  * if necessary.  Must be called with alarms blocked.
  */
@@ -193,6 +253,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 +266,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)
@@ -248,6 +312,9 @@
     struct pool *sub_prev;
     struct pool *parent;
     char *free_first_avail;
+#ifdef ALLOC_USE_MALLOC
+    void *allocation_list;
+#endif
 };
 
 pool *permanent_pool;
@@ -271,7 +338,7 @@
 
     (void) acquire_mutex(alloc_mutex);
 
-    blok = new_block(0);
+    blok = new_block(POOL_HDR_BYTES);
     new_pool = (pool *) blok->h.first_avail;
     blok->h.first_avail += POOL_HDR_BYTES;
 
@@ -318,6 +385,20 @@
 
     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);
+
+#ifdef ALLOC_USE_MALLOC
+    {
+	void *c, *n;
+
+	for (c = a->allocation_list; c; c = n) {
+	    n = *(void **)c;
+	    free(c);
+	}
+	a->allocation_list = NULL;
+    }
+#endif
 
     unblock_alarms();
 }
@@ -357,6 +438,23 @@
 
 API_EXPORT(void *) palloc(struct pool *a, int reqsize)
 {
+#ifdef ALLOC_USE_MALLOC
+    int size = reqsize + CLICK_SZ;
+    void *ptr;
+
+    block_alarms();
+    ptr = malloc(size);
+    if (ptr == NULL) {
+	fputs("Ouch!  Out of memory!\n", stderr);
+	exit(1);
+    }
+    debug_fill(ptr, size); /* might as well get uninitialized protection */
+    *(void **)ptr = a->allocation_list;
+    a->allocation_list = ptr;
+    unblock_alarms();
+    return (char *)ptr + CLICK_SZ;
+#else
+
     /* Round up requested size to an even number of alignment units (core clicks)
      */
 
@@ -377,6 +475,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;
     }
@@ -399,6 +499,7 @@
     blok->h.first_avail += size;
 
     return (void *) first_avail;
+#endif
 }
 
 API_EXPORT(void *) pcalloc(struct pool *a, int size)
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 23:32:59
@@ -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 {
Index: main/http_request.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_request.c,v
retrieving revision 1.88
diff -u -r1.88 http_request.c
--- http_request.c	1997/10/07 05:27:08	1.88
+++ http_request.c	1997/10/08 23:32:59
@@ -364,8 +364,10 @@
      * We will use test_dirname as scratch space while we build directory
      * names during the walk.  Profiling shows directory_walk to be a busy
      * function so we try to avoid allocating lots of extra memory here.
+     * We need 2 extra bytes, one for trailing \0 and one because
+     * make_dirstr_prefix will add potentially one extra /.
      */
-    test_dirname = palloc(r->pool, test_filename_len + 1);
+    test_dirname = palloc(r->pool, test_filename_len + 2);
 
     /* j keeps track of which section we're on, see core_reorder_directories */
     j = 0;


Mime
View raw message