xref: /dragonfly/contrib/lvm2/dist/libdm/mm/dbg_malloc.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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 
dm_strdup_aux(const char * str,const char * file,int line)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 
dm_malloc_aux_debug(size_t s,const char * file,int line)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 
dm_free_aux(void * p)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 
dm_realloc_aux(void * p,unsigned int s,const char * file,int line)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 
dm_dump_memory_debug(void)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 
dm_bounds_check_debug(void)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 
dm_malloc_aux(size_t s,const char * file __attribute ((unused)),int line __attribute ((unused)))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