apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gst...@apache.org
Subject cvs commit: apr/lib apr_pools.c
Date Thu, 26 Apr 2001 15:30:54 GMT
gstein      01/04/26 08:30:54

  Modified:    lib      apr_pools.c
  Log:
  Add a nifty memory/pool debugging option: allocation everything on a page,
  then turn the page inaccessible at "free" time. Causes segfaults on access.
  
  Chews memory like nothing else, but it works really well (it helped me find
  a use-after-destroy problem already). Memory consumption can be reduced by
  reimplementing this to not require the ALLOC_USE_MALLOC option.
  
  Revision  Changes    Path
  1.94      +88 -12    apr/lib/apr_pools.c
  
  Index: apr_pools.c
  ===================================================================
  RCS file: /home/cvs/apr/lib/apr_pools.c,v
  retrieving revision 1.93
  retrieving revision 1.94
  diff -u -u -r1.93 -r1.94
  --- apr_pools.c	2001/04/17 10:49:02	1.93
  +++ apr_pools.c	2001/04/26 15:30:52	1.94
  @@ -106,10 +106,32 @@
   #endif
   
   /* Details of the debugging options can now be found in the developer
  - * section of the documentaion. */
  + * section of the documentaion.
  + * ### gjs: where the hell is that?
  + *
  + * DEBUG_WITH_MPROTECT:
  + *    This is known to work on Linux systems. It can only be used in
  + *    conjunction with ALLOC_USE_MALLOC (for now). ALLOC_USE_MALLOC will
  + *    use malloc() for *each* allocation, and then free it when the pool
  + *    is cleared. When DEBUG_WITH_MPROTECT is used, the allocation is
  + *    performed using an anonymous mmap() call to get page-aligned memory.
  + *    Rather than free'ing the memory, an mprotect() call is made to make
  + *    the memory non-accessible. Thus, if the memory is referred to *after*
  + *    the pool is cleared, an immediate segfault occurs. :-)
  + *
  + *    WARNING: Since every allocation creates a new mmap, aligned on a new
  + *             page, this debugging option chews memory. A **LOT** of
  + *             memory. Linux "recovered" the memory from my X Server process
  + *             the first time I ran a "largish" sequence of operations.
  + *
  + *    ### it should be possible to use this option without ALLOC_USE_MALLOC
  + *    ### and simply mprotect the blocks at clear time (rather than put them
  + *    ### into the free block list).
  + */
   /*
   #define ALLOC_DEBUG
   #define ALLOC_STATS
  +#define DEBUG_WITH_MPROTECT
   */
   
   /* magic numbers --- min free bytes to consider a free apr_pool_t block useable,
  @@ -141,8 +163,12 @@
   #define BLOCK_MINALLOC	0
   #endif /* ALLOC_USE_MALLOC */
   
  -#define APR_SLACK_LOW    1
  -#define APR_SLACK_HIGH   2
  +#ifdef DEBUG_WITH_MPROTECT
  +#ifndef ALLOC_USE_MALLOC
  +#error "ALLOC_USE_MALLOC must be enabled to use DEBUG_WITH_MPROTECT"
  +#endif
  +#include <sys/mman.h>
  +#endif
   
   
   /*****************************************************************
  @@ -238,11 +264,62 @@
   #define debug_verify_filled(a,b,c)
   #endif /* ALLOC_DEBUG */
   
  +#ifdef DEBUG_WITH_MPROTECT
  +
  +#define SIZEOF_BLOCK(p) (((union block_hdr *)(p) - 1)->a.l)
  +
  +static void *mprotect_malloc(apr_size_t size)
  +{
  +    union block_hdr * addr;
  +
  +    size += sizeof(union block_hdr);
  +    addr = mmap(NULL, size + sizeof(union block_hdr),
  +                PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
  +                -1, 0);
  +    if (addr == MAP_FAILED)
  +        return NULL;
  +    addr->a.l = size;
  +    return addr + 1;
  +}
  +
  +static void mprotect_free(void *addr)
  +{
  +    apr_size_t size = SIZEOF_BLOCK(addr);
  +    int rv = mprotect((union block_hdr *)addr - 1, size, PROT_NONE);
  +    if (rv != 0) {
  +        fprintf(stderr, "could not protect. errno=%d\n", errno);
  +        abort();
  +    }
  +}
  +
  +static void *mprotect_realloc(void *addr, apr_size_t size)
  +{
  +    void *new_addr = mprotect_malloc(size);
  +    apr_size_t old_size = SIZEOF_BLOCK(addr);
  +
  +    if (size < old_size)
  +        old_size = size;
  +    memcpy(new_addr, addr, old_size);
  +    mprotect_free(addr);
  +    return new_addr;
  +}
  +
  +#define DO_MALLOC(s) mprotect_malloc(s)
  +#define DO_FREE(p) mprotect_free(p)
  +#define DO_REALLOC(p,s) mprotect_realloc(p,s)
  +
  +#else /* DEBUG_WITH_MPROTECT */
  +
  +#define DO_MALLOC(s) malloc(s)
  +#define DO_FREE(p) free(p)
  +#define DO_REALLOC(p,s) realloc(p,s)
  +
  +#endif /* DEBUG_WITH_MPROTECT */
  +    
   /*
    * Get a completely new block from the system pool. Note that we rely on
    * malloc() to provide aligned memory.
    */
  -
   static union block_hdr *malloc_block(int size, int (*apr_abort)(int retcode))
   {
       union block_hdr *blok;
  @@ -259,7 +336,7 @@
       num_malloc_bytes += size + sizeof(union block_hdr);
   #endif /* ALLOC_STATS */
   
  -    blok = (union block_hdr *) malloc(size + sizeof(union block_hdr));
  +    blok = (union block_hdr *) DO_MALLOC(size + sizeof(union block_hdr));
       APR_ABORT(blok == NULL, APR_ENOMEM, apr_abort,
                 "Ouch!  malloc failed in malloc_block()\n");
       debug_fill(blok, size + sizeof(union block_hdr));
  @@ -311,7 +388,7 @@
   
       for ( ; blok; blok = next) {
   	next = blok->h.next;
  -	free(blok);
  +	DO_FREE(blok);
       }
   #else /* ALLOC_USE_MALLOC */
   
  @@ -395,7 +472,6 @@
    * Get a new block, from our own free list if possible, from the system
    * if necessary.  Must be called with alarms blocked.
    */
  -
   static union block_hdr *new_block(int min_size, int (*apr_abort)(int retcode))
   {
       union block_hdr **lastptr = &block_freelist;
  @@ -766,7 +842,7 @@
   
   	for (c = a->allocation_list; c; c = n) {
   	    n = *(void **)c;
  -	    free(c);
  +	    DO_FREE(c);
   	}
   	a->allocation_list = NULL;
       }
  @@ -947,7 +1023,7 @@
       apr_size_t size = reqsize + CLICK_SZ;
       void *ptr;
   
  -    ptr = malloc(size);
  +    ptr = DO_MALLOC(size);
       if (ptr == NULL) {
   	fputs("Ouch!  Out of memory!\n", stderr);
   	exit(1);
  @@ -1104,7 +1180,7 @@
       char *ptr;
   
       size = (char *)ps->vbuff.curpos - ps->base;
  -    ptr = realloc(ps->base, 2*size);
  +    ptr = DO_REALLOC(ps->base, 2*size);
       if (ptr == NULL) {
   	fputs("Ouch!  Out of memory!\n", stderr);
   	exit(1);
  @@ -1164,7 +1240,7 @@
       struct psprintf_data ps;
       void *ptr;
   
  -    ps.base = malloc(512);
  +    ps.base = DO_MALLOC(512);
       if (ps.base == NULL) {
   	fputs("Ouch!  Out of memory!\n", stderr);
   	exit(1);
  @@ -1176,7 +1252,7 @@
       *ps.vbuff.curpos++ = '\0';
       ptr = ps.base;
       /* shrink */
  -    ptr = realloc(ptr, (char *)ps.vbuff.curpos - (char *)ptr);
  +    ptr = DO_REALLOC(ptr, (char *)ps.vbuff.curpos - (char *)ptr);
       if (ptr == NULL) {
   	fputs("Ouch!  Out of memory!\n", stderr);
   	exit(1);
  
  
  

Mime
View raw message