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