direct-io.hg

changeset 12295:092170a14212

[XEN] Add debug mode to xmalloc().

This detects programming mistakes such as:
* double free
* use after free
* write beyond bounds of allocation

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Nov 08 10:48:21 2006 +0000 (2006-11-08)
parents ec4f43a4730f
children 1fcdb3a35db3
files xen/common/xmalloc.c
line diff
     1.1 --- a/xen/common/xmalloc.c	Wed Nov 08 09:50:09 2006 +0000
     1.2 +++ b/xen/common/xmalloc.c	Wed Nov 08 10:48:21 2006 +0000
     1.3 @@ -34,16 +34,81 @@
     1.4  #include <xen/cache.h>
     1.5  #include <xen/prefetch.h>
     1.6  
     1.7 +/*
     1.8 + * XMALLOC_DEBUG:
     1.9 + *  1. Free data blocks are filled with poison bytes.
    1.10 + *  2. In-use data blocks have guard bytes at the start and end.
    1.11 + */
    1.12 +#ifndef NDEBUG
    1.13 +#define XMALLOC_DEBUG 1
    1.14 +#endif
    1.15 +
    1.16  static LIST_HEAD(freelist);
    1.17  static DEFINE_SPINLOCK(freelist_lock);
    1.18  
    1.19  struct xmalloc_hdr
    1.20  {
    1.21 -    /* Total including this hdr. */
    1.22 +    /* Size is total including this header. */
    1.23      size_t size;
    1.24      struct list_head freelist;
    1.25  } __cacheline_aligned;
    1.26  
    1.27 +static void add_to_freelist(struct xmalloc_hdr *hdr)
    1.28 +{
    1.29 +#if XMALLOC_DEBUG
    1.30 +    memset(hdr + 1, 0xa5, hdr->size - sizeof(*hdr));
    1.31 +#endif
    1.32 +    list_add(&hdr->freelist, &freelist);
    1.33 +}
    1.34 +
    1.35 +static void del_from_freelist(struct xmalloc_hdr *hdr)
    1.36 +{
    1.37 +#if XMALLOC_DEBUG
    1.38 +    size_t i;
    1.39 +    unsigned char *data = (unsigned char *)(hdr + 1);
    1.40 +    for ( i = 0; i < (hdr->size - sizeof(*hdr)); i++ )
    1.41 +        BUG_ON(data[i] != 0xa5);
    1.42 +    BUG_ON((hdr->size <= 0) || (hdr->size >= PAGE_SIZE));
    1.43 +#endif
    1.44 +    list_del(&hdr->freelist);
    1.45 +}
    1.46 +
    1.47 +static void *data_from_header(struct xmalloc_hdr *hdr)
    1.48 +{
    1.49 +#if XMALLOC_DEBUG
    1.50 +    /* Data block contain SMP_CACHE_BYTES of guard canary. */
    1.51 +    unsigned char *data = (unsigned char *)(hdr + 1);
    1.52 +    memset(data, 0x5a, SMP_CACHE_BYTES);
    1.53 +    memset(data + hdr->size - sizeof(*hdr) - SMP_CACHE_BYTES,
    1.54 +           0x5a, SMP_CACHE_BYTES);
    1.55 +    return data + SMP_CACHE_BYTES;
    1.56 +#else
    1.57 +    return hdr + 1;
    1.58 +#endif
    1.59 +}
    1.60 +
    1.61 +static struct xmalloc_hdr *header_from_data(const void *p)
    1.62 +{
    1.63 +#if XMALLOC_DEBUG
    1.64 +    unsigned char *data = (unsigned char *)p - SMP_CACHE_BYTES;
    1.65 +    struct xmalloc_hdr *hdr = (struct xmalloc_hdr *)data - 1;
    1.66 +    size_t i;
    1.67 +
    1.68 +    /* Check header guard canary. */
    1.69 +    for ( i = 0; i < SMP_CACHE_BYTES; i++ )
    1.70 +        BUG_ON(data[i] != 0x5a);
    1.71 +
    1.72 +    /* Check footer guard canary. */
    1.73 +    data += hdr->size - sizeof(*hdr) - SMP_CACHE_BYTES;
    1.74 +    for ( i = 0; i < SMP_CACHE_BYTES; i++ )
    1.75 +        BUG_ON(data[i] != 0x5a);
    1.76 +
    1.77 +    return hdr;
    1.78 +#else
    1.79 +    return (struct xmalloc_hdr *)p - 1;
    1.80 +#endif
    1.81 +}
    1.82 +
    1.83  static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block)
    1.84  {
    1.85      struct xmalloc_hdr *extra;
    1.86 @@ -54,7 +119,7 @@ static void maybe_split(struct xmalloc_h
    1.87      {
    1.88          extra = (struct xmalloc_hdr *)((unsigned long)hdr + size);
    1.89          extra->size = leftover;
    1.90 -        list_add(&extra->freelist, &freelist);
    1.91 +        add_to_freelist(extra);
    1.92      }
    1.93      else
    1.94      {
    1.95 @@ -79,7 +144,7 @@ static void *xmalloc_new_page(size_t siz
    1.96      maybe_split(hdr, size, PAGE_SIZE);
    1.97      spin_unlock_irqrestore(&freelist_lock, flags);
    1.98  
    1.99 -    return hdr+1;
   1.100 +    return data_from_header(hdr);
   1.101  }
   1.102  
   1.103  /* Big object?  Just use the page allocator. */
   1.104 @@ -96,7 +161,7 @@ static void *xmalloc_whole_pages(size_t 
   1.105      /* Debugging aid. */
   1.106      hdr->freelist.next = hdr->freelist.prev = NULL;
   1.107  
   1.108 -    return hdr+1;
   1.109 +    return data_from_header(hdr);
   1.110  }
   1.111  
   1.112  /* Return size, increased to alignment with align. */
   1.113 @@ -113,6 +178,11 @@ void *_xmalloc(size_t size, size_t align
   1.114      /* We currently always return cacheline aligned. */
   1.115      BUG_ON(align > SMP_CACHE_BYTES);
   1.116  
   1.117 +#if XMALLOC_DEBUG
   1.118 +    /* Add room for canaries at start and end of data block. */
   1.119 +    size += 2 * SMP_CACHE_BYTES;
   1.120 +#endif
   1.121 +
   1.122      /* Add room for header, pad to align next header. */
   1.123      size += sizeof(struct xmalloc_hdr);
   1.124      size = align_up(size, __alignof__(struct xmalloc_hdr));
   1.125 @@ -127,10 +197,10 @@ void *_xmalloc(size_t size, size_t align
   1.126      {
   1.127          if ( i->size < size )
   1.128              continue;
   1.129 -        list_del(&i->freelist);
   1.130 +        del_from_freelist(i);
   1.131          maybe_split(i, size, i->size);
   1.132          spin_unlock_irqrestore(&freelist_lock, flags);
   1.133 -        return i+1;
   1.134 +        return data_from_header(i);
   1.135      }
   1.136      spin_unlock_irqrestore(&freelist_lock, flags);
   1.137  
   1.138 @@ -146,7 +216,7 @@ void xfree(const void *p)
   1.139      if ( p == NULL )
   1.140          return;
   1.141  
   1.142 -    hdr = (struct xmalloc_hdr *)p - 1;
   1.143 +    hdr = header_from_data(p);
   1.144  
   1.145      /* We know hdr will be on same page. */
   1.146      BUG_ON(((long)p & PAGE_MASK) != ((long)hdr & PAGE_MASK));
   1.147 @@ -175,7 +245,7 @@ void xfree(const void *p)
   1.148          /* We follow this block?  Swallow it. */
   1.149          if ( (_i + i->size) == _hdr )
   1.150          {
   1.151 -            list_del(&i->freelist);
   1.152 +            del_from_freelist(i);
   1.153              i->size += hdr->size;
   1.154              hdr = i;
   1.155          }
   1.156 @@ -183,7 +253,7 @@ void xfree(const void *p)
   1.157          /* We precede this block? Swallow it. */
   1.158          if ( (_hdr + hdr->size) == _i )
   1.159          {
   1.160 -            list_del(&i->freelist);
   1.161 +            del_from_freelist(i);
   1.162              hdr->size += i->size;
   1.163          }
   1.164      }
   1.165 @@ -196,7 +266,7 @@ void xfree(const void *p)
   1.166      }
   1.167      else
   1.168      {
   1.169 -        list_add(&hdr->freelist, &freelist);
   1.170 +        add_to_freelist(hdr);
   1.171      }
   1.172  
   1.173      spin_unlock_irqrestore(&freelist_lock, flags);