dbg_malloc.c revision 1.1.1.2 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