1 /* $NetBSD: dbg_malloc.c,v 1.1.1.2 2009/12/02 00:26:09 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6 * 7 * This file is part of the device-mapper userspace tools. 8 * 9 * This copyrighted material is made available to anyone wishing to use, 10 * modify, copy, or redistribute it subject to the terms and conditions 11 * of the GNU Lesser General Public License v.2.1. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software Foundation, 15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 18 #include "dmlib.h" 19 20 #include <assert.h> 21 #include <stdarg.h> 22 23 char *dm_strdup_aux(const char *str, const char *file, int line) 24 { 25 char *ret; 26 27 if (!str) { 28 log_error("Internal error: dm_strdup called with NULL pointer"); 29 return NULL; 30 } 31 32 if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line))) 33 strcpy(ret, str); 34 35 return ret; 36 } 37 38 struct memblock { 39 struct memblock *prev, *next; /* All allocated blocks are linked */ 40 size_t length; /* Size of the requested block */ 41 int id; /* Index of the block */ 42 const char *file; /* File that allocated */ 43 int line; /* Line that allocated */ 44 void *magic; /* Address of this block */ 45 } __attribute__((aligned(8))); 46 47 static struct { 48 unsigned block_serialno;/* Non-decreasing serialno of block */ 49 unsigned blocks_allocated; /* Current number of blocks allocated */ 50 unsigned blocks_max; /* Max no of concurrently-allocated blocks */ 51 unsigned int bytes, mbytes; 52 53 } _mem_stats = { 54 0, 0, 0, 0, 0}; 55 56 static struct memblock *_head = 0; 57 static struct memblock *_tail = 0; 58 59 void *dm_malloc_aux_debug(size_t s, const char *file, int line) 60 { 61 struct memblock *nb; 62 size_t tsize = s + sizeof(*nb) + sizeof(unsigned long); 63 64 if (s > 50000000) { 65 log_error("Huge memory allocation (size %" PRIsize_t 66 ") rejected - metadata corruption?", s); 67 return 0; 68 } 69 70 if (!(nb = malloc(tsize))) { 71 log_error("couldn't allocate any memory, size = %" PRIsize_t, 72 s); 73 return 0; 74 } 75 76 /* set up the file and line info */ 77 nb->file = file; 78 nb->line = line; 79 80 dm_bounds_check(); 81 82 /* setup fields */ 83 nb->magic = nb + 1; 84 nb->length = s; 85 nb->id = ++_mem_stats.block_serialno; 86 nb->next = 0; 87 88 /* stomp a pretty pattern across the new memory 89 and fill in the boundary bytes */ 90 { 91 char *ptr = (char *) (nb + 1); 92 size_t i; 93 for (i = 0; i < s; i++) 94 *ptr++ = i & 0x1 ? (char) 0xba : (char) 0xbe; 95 96 for (i = 0; i < sizeof(unsigned long); i++) 97 *ptr++ = (char) nb->id; 98 } 99 100 nb->prev = _tail; 101 102 /* link to tail of the list */ 103 if (!_head) 104 _head = _tail = nb; 105 else { 106 _tail->next = nb; 107 _tail = nb; 108 } 109 110 _mem_stats.blocks_allocated++; 111 if (_mem_stats.blocks_allocated > _mem_stats.blocks_max) 112 _mem_stats.blocks_max = _mem_stats.blocks_allocated; 113 114 _mem_stats.bytes += s; 115 if (_mem_stats.bytes > _mem_stats.mbytes) 116 _mem_stats.mbytes = _mem_stats.bytes; 117 118 /* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated, 119 _mem_stats.bytes); */ 120 121 return nb + 1; 122 } 123 124 void dm_free_aux(void *p) 125 { 126 char *ptr; 127 size_t i; 128 struct memblock *mb = ((struct memblock *) p) - 1; 129 if (!p) 130 return; 131 132 dm_bounds_check(); 133 134 /* sanity check */ 135 assert(mb->magic == p); 136 137 /* check data at the far boundary */ 138 ptr = ((char *) mb) + sizeof(struct memblock) + mb->length; 139 for (i = 0; i < sizeof(unsigned long); i++) 140 if (*ptr++ != (char) mb->id) 141 assert(!"Damage at far end of block"); 142 143 /* have we freed this before ? */ 144 assert(mb->id != 0); 145 146 /* unlink */ 147 if (mb->prev) 148 mb->prev->next = mb->next; 149 else 150 _head = mb->next; 151 152 if (mb->next) 153 mb->next->prev = mb->prev; 154 else 155 _tail = mb->prev; 156 157 mb->id = 0; 158 159 /* stomp a different pattern across the memory */ 160 ptr = ((char *) mb) + sizeof(struct memblock); 161 for (i = 0; i < mb->length; i++) 162 *ptr++ = i & 1 ? (char) 0xde : (char) 0xad; 163 164 assert(_mem_stats.blocks_allocated); 165 _mem_stats.blocks_allocated--; 166 _mem_stats.bytes -= mb->length; 167 168 /* free the memory */ 169 free(mb); 170 } 171 172 void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line) 173 { 174 void *r; 175 struct memblock *mb = ((struct memblock *) p) - 1; 176 177 r = dm_malloc_aux_debug(s, file, line); 178 179 if (p) { 180 memcpy(r, p, mb->length); 181 dm_free_aux(p); 182 } 183 184 return r; 185 } 186 187 int dm_dump_memory_debug(void) 188 { 189 unsigned long tot = 0; 190 struct memblock *mb; 191 char str[32]; 192 size_t c; 193 194 if (_head) 195 log_very_verbose("You have a memory leak:"); 196 197 for (mb = _head; mb; mb = mb->next) { 198 for (c = 0; c < sizeof(str) - 1; c++) { 199 if (c >= mb->length) 200 str[c] = ' '; 201 else if (*(char *)(mb->magic + c) == '\0') 202 str[c] = '\0'; 203 else if (*(char *)(mb->magic + c) < ' ') 204 str[c] = '?'; 205 else 206 str[c] = *(char *)(mb->magic + c); 207 } 208 str[sizeof(str) - 1] = '\0'; 209 210 LOG_MESG(_LOG_INFO, mb->file, mb->line, 0, 211 "block %d at %p, size %" PRIsize_t "\t [%s]", 212 mb->id, mb->magic, mb->length, str); 213 tot += mb->length; 214 } 215 216 if (_head) 217 log_very_verbose("%ld bytes leaked in total", tot); 218 219 return 1; 220 } 221 222 void dm_bounds_check_debug(void) 223 { 224 struct memblock *mb = _head; 225 while (mb) { 226 size_t i; 227 char *ptr = ((char *) (mb + 1)) + mb->length; 228 for (i = 0; i < sizeof(unsigned long); i++) 229 if (*ptr++ != (char) mb->id) 230 assert(!"Memory smash"); 231 232 mb = mb->next; 233 } 234 } 235 236 void *dm_malloc_aux(size_t s, const char *file __attribute((unused)), 237 int line __attribute((unused))) 238 { 239 if (s > 50000000) { 240 log_error("Huge memory allocation (size %" PRIsize_t 241 ") rejected - metadata corruption?", s); 242 return 0; 243 } 244 245 return malloc(s); 246 } 247