Sync usage with man page.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / libdm / mm / dbg_malloc.c
blobfb4f181c75725bf0b2b513eccccf6323c88aad05
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of the device-mapper userspace tools.
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.
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
18 #include "dmlib.h"
20 #include <assert.h>
21 #include <stdarg.h>
23 char *dm_strdup_aux(const char *str, const char *file, int line)
25 char *ret;
27 if (!str) {
28 log_error("Internal error: dm_strdup called with NULL pointer");
29 return NULL;
32 if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
33 strcpy(ret, str);
35 return ret;
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)));
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;
53 } _mem_stats = {
54 0, 0, 0, 0, 0};
56 static struct memblock *_head = 0;
57 static struct memblock *_tail = 0;
59 void *dm_malloc_aux_debug(size_t s, const char *file, int line)
61 struct memblock *nb;
62 size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
64 if (s > 50000000) {
65 log_error("Huge memory allocation (size %" PRIsize_t
66 ") rejected - metadata corruption?", s);
67 return 0;
70 if (!(nb = malloc(tsize))) {
71 log_error("couldn't allocate any memory, size = %" PRIsize_t,
72 s);
73 return 0;
76 /* set up the file and line info */
77 nb->file = file;
78 nb->line = line;
80 dm_bounds_check();
82 /* setup fields */
83 nb->magic = nb + 1;
84 nb->length = s;
85 nb->id = ++_mem_stats.block_serialno;
86 nb->next = 0;
88 /* stomp a pretty pattern across the new memory
89 and fill in the boundary bytes */
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;
96 for (i = 0; i < sizeof(unsigned long); i++)
97 *ptr++ = (char) nb->id;
100 nb->prev = _tail;
102 /* link to tail of the list */
103 if (!_head)
104 _head = _tail = nb;
105 else {
106 _tail->next = nb;
107 _tail = nb;
110 _mem_stats.blocks_allocated++;
111 if (_mem_stats.blocks_allocated > _mem_stats.blocks_max)
112 _mem_stats.blocks_max = _mem_stats.blocks_allocated;
114 _mem_stats.bytes += s;
115 if (_mem_stats.bytes > _mem_stats.mbytes)
116 _mem_stats.mbytes = _mem_stats.bytes;
118 /* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
119 _mem_stats.bytes); */
121 return nb + 1;
124 void dm_free_aux(void *p)
126 char *ptr;
127 size_t i;
128 struct memblock *mb = ((struct memblock *) p) - 1;
129 if (!p)
130 return;
132 dm_bounds_check();
134 /* sanity check */
135 assert(mb->magic == p);
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");
143 /* have we freed this before ? */
144 assert(mb->id != 0);
146 /* unlink */
147 if (mb->prev)
148 mb->prev->next = mb->next;
149 else
150 _head = mb->next;
152 if (mb->next)
153 mb->next->prev = mb->prev;
154 else
155 _tail = mb->prev;
157 mb->id = 0;
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;
164 assert(_mem_stats.blocks_allocated);
165 _mem_stats.blocks_allocated--;
166 _mem_stats.bytes -= mb->length;
168 /* free the memory */
169 free(mb);
172 void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
174 void *r;
175 struct memblock *mb = ((struct memblock *) p) - 1;
177 r = dm_malloc_aux_debug(s, file, line);
179 if (p) {
180 memcpy(r, p, mb->length);
181 dm_free_aux(p);
184 return r;
187 int dm_dump_memory_debug(void)
189 unsigned long tot = 0;
190 struct memblock *mb;
191 char str[32];
192 size_t c;
194 if (_head)
195 log_very_verbose("You have a memory leak:");
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);
208 str[sizeof(str) - 1] = '\0';
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;
216 if (_head)
217 log_very_verbose("%ld bytes leaked in total", tot);
219 return 1;
222 void dm_bounds_check_debug(void)
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");
232 mb = mb->next;
236 void *dm_malloc_aux(size_t s, const char *file __attribute((unused)),
237 int line __attribute((unused)))
239 if (s > 50000000) {
240 log_error("Huge memory allocation (size %" PRIsize_t
241 ") rejected - metadata corruption?", s);
242 return 0;
245 return malloc(s);