Branch data Line data Source code
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 : 16 : char *dm_strdup_aux(const char *str, const char *file, int line)
22 : : {
23 : : char *ret;
24 : :
25 [ - + ]: 16 : if (!str) {
26 [ # # ]: 0 : log_error(INTERNAL_ERROR "dm_strdup called with NULL pointer");
27 : 0 : return NULL;
28 : : }
29 : :
30 [ + - ]: 16 : if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
31 : 16 : strcpy(ret, str);
32 : :
33 : 16 : 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 : 2468 : void *dm_malloc_aux_debug(size_t s, const char *file, int line)
58 : : {
59 : : struct memblock *nb;
60 : 2468 : size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
61 : :
62 [ - + ]: 2468 : 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 [ - + ]: 2468 : 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 : 2468 : nb->file = file;
76 : 2468 : nb->line = line;
77 : :
78 : 2468 : dm_bounds_check();
79 : :
80 : : /* setup fields */
81 : 2468 : nb->magic = nb + 1;
82 : 2468 : nb->length = s;
83 : 2468 : nb->id = ++_mem_stats.block_serialno;
84 : 2468 : nb->next = 0;
85 : :
86 : : /* stomp a pretty pattern across the new memory
87 : : and fill in the boundary bytes */
88 : : {
89 : 2468 : char *ptr = (char *) (nb + 1);
90 : : size_t i;
91 [ + + ]: 25528247 : for (i = 0; i < s; i++)
92 [ + + ]: 25525779 : *ptr++ = i & 0x1 ? (char) 0xba : (char) 0xbe;
93 : :
94 [ + + ]: 12340 : for (i = 0; i < sizeof(unsigned long); i++)
95 : 9872 : *ptr++ = (char) nb->id;
96 : : }
97 : :
98 : 2468 : nb->prev = _tail;
99 : :
100 : : /* link to tail of the list */
101 [ + + ]: 2468 : if (!_head)
102 : 1 : _head = _tail = nb;
103 : : else {
104 : 2467 : _tail->next = nb;
105 : 2467 : _tail = nb;
106 : : }
107 : :
108 : 2468 : _mem_stats.blocks_allocated++;
109 [ + + ]: 2468 : if (_mem_stats.blocks_allocated > _mem_stats.blocks_max)
110 : 1599 : _mem_stats.blocks_max = _mem_stats.blocks_allocated;
111 : :
112 : 2468 : _mem_stats.bytes += s;
113 [ + + ]: 2468 : if (_mem_stats.bytes > _mem_stats.mbytes)
114 : 1547 : _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 : 2468 : return nb + 1;
120 : : }
121 : :
122 : 2497 : void dm_free_aux(void *p)
123 : : {
124 : : char *ptr;
125 : : size_t i;
126 : 2497 : struct memblock *mb = ((struct memblock *) p) - 1;
127 [ + + ]: 2497 : if (!p)
128 : 29 : return;
129 : :
130 : 2468 : dm_bounds_check();
131 : :
132 : : /* sanity check */
133 [ - + ]: 2468 : assert(mb->magic == p);
134 : :
135 : : /* check data at the far boundary */
136 : 2468 : ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
137 [ + + ]: 12340 : for (i = 0; i < sizeof(unsigned long); i++)
138 [ - + ]: 9872 : if (*ptr++ != (char) mb->id)
139 : 0 : assert(!"Damage at far end of block");
140 : :
141 : : /* have we freed this before ? */
142 [ - + ]: 2468 : assert(mb->id != 0);
143 : :
144 : : /* unlink */
145 [ + + ]: 2468 : if (mb->prev)
146 : 2467 : mb->prev->next = mb->next;
147 : : else
148 : 1 : _head = mb->next;
149 : :
150 [ + + ]: 2468 : if (mb->next)
151 : 2170 : mb->next->prev = mb->prev;
152 : : else
153 : 298 : _tail = mb->prev;
154 : :
155 : 2468 : mb->id = 0;
156 : :
157 : : /* stomp a different pattern across the memory */
158 : 2468 : ptr = ((char *) mb) + sizeof(struct memblock);
159 [ + + ]: 25528247 : for (i = 0; i < mb->length; i++)
160 [ + + ]: 25525779 : *ptr++ = i & 1 ? (char) 0xde : (char) 0xad;
161 : :
162 [ - + ]: 2468 : assert(_mem_stats.blocks_allocated);
163 : 2468 : _mem_stats.blocks_allocated--;
164 : 2468 : _mem_stats.bytes -= mb->length;
165 : :
166 : : /* free the memory */
167 : 2497 : free(mb);
168 : : }
169 : :
170 : 2 : void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
171 : : {
172 : : void *r;
173 : 2 : struct memblock *mb = ((struct memblock *) p) - 1;
174 : :
175 : 2 : r = dm_malloc_aux_debug(s, file, line);
176 : :
177 [ + + ]: 2 : if (p) {
178 : 1 : memcpy(r, p, mb->length);
179 : 1 : dm_free_aux(p);
180 : : }
181 : :
182 : 2 : 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 : 4936 : void dm_bounds_check_debug(void)
221 : : {
222 : 4936 : struct memblock *mb = _head;
223 [ + + ]: 2941760 : while (mb) {
224 : : size_t i;
225 : 2936824 : char *ptr = ((char *) (mb + 1)) + mb->length;
226 [ + + ]: 14684120 : for (i = 0; i < sizeof(unsigned long); i++)
227 [ - + ]: 11747296 : if (*ptr++ != (char) mb->id)
228 : 0 : assert(!"Memory smash");
229 : :
230 : 2936824 : mb = mb->next;
231 : : }
232 : 4936 : }
233 : :
234 : 0 : void *dm_malloc_aux(size_t s, const char *file __attribute((unused)),
235 : : int line __attribute((unused)))
236 : : {
237 [ # # ]: 0 : 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 : 0 : return malloc(s);
244 : : }
|