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