Branch data Line data Source code
1 : : /*
2 : : * Memory manipulation routines
3 : : * (c) Thomas Pornin 1998 - 2002
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions
7 : : * are met:
8 : : * 1. Redistributions of source code must retain the above copyright
9 : : * notice, this list of conditions and the following disclaimer.
10 : : * 2. Redistributions in binary form must reproduce the above copyright
11 : : * notice, this list of conditions and the following disclaimer in the
12 : : * documentation and/or other materials provided with the distribution.
13 : : * 4. The name of the authors may not be used to endorse or promote
14 : : * products derived from this software without specific prior written
15 : : * permission.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 : : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
21 : : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 : : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23 : : * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 : : * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 : : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 : : * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 : : * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : *
29 : : */
30 : :
31 : : #include "mem.h"
32 : : #include <stdio.h>
33 : : #include <stdlib.h>
34 : : #include <string.h>
35 : :
36 : : /*
37 : : * Shifting a pointer of that some bytes is supposed to satisfy
38 : : * alignment requirements. This is *not* guaranteed by the standard
39 : : * but should work everywhere anyway.
40 : : */
41 : : #define ALIGNSHIFT (sizeof(long) > sizeof(long double) \
42 : : ? sizeof(long) : sizeof(long double))
43 : :
44 : : #ifdef AUDIT
45 : : void die(void)
46 : : {
47 : : abort();
48 : : }
49 : :
50 : : static void suicide(unsigned long e)
51 : : {
52 : : fprintf(stderr, "ouch: Schrodinger's beef is not dead ! %lx\n", e);
53 : : die();
54 : : }
55 : : #else
56 : 0 : void die(void)
57 : : {
58 : 0 : exit(EXIT_FAILURE);
59 : : }
60 : : #endif
61 : :
62 : : #if defined AUDIT || defined MEM_CHECK || defined MEM_DEBUG
63 : : /*
64 : : * This function is equivalent to a malloc(), but will display an error
65 : : * message and exit if the wanted memory is not available
66 : : */
67 : : #ifdef MEM_DEBUG
68 : : static void *getmem_raw(size_t x)
69 : : #else
70 : : void *(getmem)(size_t x)
71 : : #endif
72 : : {
73 : : void *m;
74 : :
75 : : #ifdef AUDIT
76 : : m = malloc(x + ALIGNSHIFT);
77 : : #else
78 : : m = malloc(x);
79 : : #endif
80 : : if (m == 0) {
81 : : fprintf(stderr, "ouch: malloc() failed\n");
82 : : die();
83 : : }
84 : : #ifdef AUDIT
85 : : *((unsigned long *)m) = 0xdeadbeefUL;
86 : : return (void *)(((char *)m) + ALIGNSHIFT);
87 : : #else
88 : : return m;
89 : : #endif
90 : : }
91 : : #endif
92 : :
93 : : #ifndef MEM_DEBUG
94 : : /*
95 : : * This function is equivalent to a realloc(); if the realloc() call
96 : : * fails, it will try a malloc() and a memcpy(). If not enough memory is
97 : : * available, the program exits with an error message
98 : : */
99 : 99436 : void *(incmem)(void *m, size_t x, size_t nx)
100 : : {
101 : : void *nm;
102 : :
103 : : #ifdef AUDIT
104 : : m = (void *)(((char *)m) - ALIGNSHIFT);
105 : : if (*((unsigned long *)m) != 0xdeadbeefUL)
106 : : suicide(*((unsigned long *)m));
107 : : x += ALIGNSHIFT; nx += ALIGNSHIFT;
108 : : #endif
109 [ - + ]: 99436 : if (!(nm = realloc(m, nx))) {
110 [ # # ]: 0 : if (x > nx) x = nx;
111 : 0 : nm = (getmem)(nx);
112 : 0 : memcpy(nm, m, x);
113 : : /* free() and not freemem(), because of the Schrodinger beef */
114 : 0 : free(m);
115 : : }
116 : : #ifdef AUDIT
117 : : return (void *)(((char *)nm) + ALIGNSHIFT);
118 : : #else
119 : 99436 : return nm;
120 : : #endif
121 : : }
122 : : #endif
123 : :
124 : : #if defined AUDIT || defined MEM_DEBUG
125 : : /*
126 : : * This function frees the given block
127 : : */
128 : : #ifdef MEM_DEBUG
129 : : static void freemem_raw(void *x)
130 : : #else
131 : : void (freemem)(void *x)
132 : : #endif
133 : : {
134 : : #ifdef AUDIT
135 : : void *y = (void *)(((char *)x) - ALIGNSHIFT);
136 : :
137 : : if ((*((unsigned long *)y)) != 0xdeadbeefUL)
138 : : suicide(*((unsigned long *)y));
139 : : *((unsigned long *)y) = 0xfeedbabeUL;
140 : : free(y);
141 : : #else
142 : : free(x);
143 : : #endif
144 : : }
145 : : #endif
146 : :
147 : : #ifdef AUDIT
148 : : /*
149 : : * This function copies n bytes from src to dest
150 : : */
151 : : void *mmv(void *dest, void *src, size_t n)
152 : : {
153 : : return memcpy(dest, src, n);
154 : : }
155 : :
156 : : /*
157 : : * This function copies n bytes from src to dest
158 : : */
159 : : void *mmvwo(void *dest, void *src, size_t n)
160 : : {
161 : : return memmove(dest, src, n);
162 : : }
163 : : #endif
164 : :
165 : : #ifndef MEM_DEBUG
166 : : /*
167 : : * This function creates a new char * and fills it with a copy of src
168 : : */
169 : 241104 : char *(sdup)(char *src)
170 : : {
171 : 241104 : size_t n = 1 + strlen(src);
172 : 241104 : char *x = getmem(n);
173 : :
174 : 241104 : mmv(x, src, n);
175 : 241104 : return x;
176 : : }
177 : : #endif
178 : :
179 : : #ifdef MEM_DEBUG
180 : : /*
181 : : * We include here special versions of getmem(), freemem() and incmem()
182 : : * that track allocations and are used to detect memory leaks.
183 : : *
184 : : * Each allocation is referenced in a list, with a serial number.
185 : : */
186 : :
187 : : /*
188 : : * Define "true" functions for applications that need pointers
189 : : * to such functions.
190 : : */
191 : : void *(getmem)(size_t n)
192 : : {
193 : : return getmem(n);
194 : : }
195 : :
196 : : void (freemem)(void *x)
197 : : {
198 : : freemem(x);
199 : : }
200 : :
201 : : void *(incmem)(void *x, size_t s, size_t ns)
202 : : {
203 : : return incmem(x, s, ns);
204 : : }
205 : :
206 : : char *(sdup)(char *s)
207 : : {
208 : : return sdup(s);
209 : : }
210 : :
211 : : static long current_serial = 0L;
212 : :
213 : : /* must be a power of two */
214 : : #define MEMDEBUG_MEMG 128U
215 : :
216 : : static struct mem_track {
217 : : void *block;
218 : : long serial;
219 : : char *file;
220 : : int line;
221 : : } *mem = 0;
222 : :
223 : : static size_t meml = 0;
224 : :
225 : : static unsigned int current_ptr = 0;
226 : :
227 : : static void *true_incmem(void *x, size_t old_size, size_t new_size)
228 : : {
229 : : void * y = realloc(x, new_size);
230 : :
231 : : if (y == 0) {
232 : : y = malloc(new_size);
233 : : if (y == 0) {
234 : : fprintf(stderr, "ouch: malloc() failed\n");
235 : : die();
236 : : }
237 : : mmv(y, x, old_size < new_size ? old_size : new_size);
238 : : free(x);
239 : : }
240 : : return y;
241 : : }
242 : :
243 : : static long find_free_block(void)
244 : : {
245 : : unsigned int n;
246 : : size_t i;
247 : :
248 : : for (i = 0, n = current_ptr; i < meml; i ++) {
249 : : if (mem[n].block == 0) {
250 : : current_ptr = n;
251 : : return n;
252 : : }
253 : : n = (n + 1) & (meml - 1U);
254 : : }
255 : : if (meml == 0) {
256 : : size_t j;
257 : :
258 : : meml = MEMDEBUG_MEMG;
259 : : mem = malloc(meml * sizeof(struct mem_track));
260 : : current_ptr = 0;
261 : : for (j = 0; j < meml ; j ++) mem[j].block = 0;
262 : : } else {
263 : : size_t j;
264 : :
265 : : mem = true_incmem(mem, meml * sizeof(struct mem_track),
266 : : 2 * meml * sizeof(struct mem_track));
267 : : current_ptr = meml;
268 : : for (j = meml; j < 2 * meml ; j ++) mem[j].block = 0;
269 : : meml *= 2;
270 : : }
271 : : return current_ptr;
272 : : }
273 : :
274 : : void *getmem_debug(size_t n, char *file, int line)
275 : : {
276 : : void *x = getmem_raw(n + ALIGNSHIFT);
277 : : long i = find_free_block();
278 : :
279 : : *(long *)x = i;
280 : : mem[i].block = x;
281 : : mem[i].serial = current_serial ++;
282 : : mem[i].file = file;
283 : : mem[i].line = line;
284 : : return (void *)((unsigned char *)x + ALIGNSHIFT);
285 : : }
286 : :
287 : : void freemem_debug(void *x, char *file, int line)
288 : : {
289 : : void *y = (unsigned char *)x - ALIGNSHIFT;
290 : : long i = *(long *)y;
291 : :
292 : : if (i < 0 || (size_t)i >= meml || mem[i].block != y) {
293 : : fprintf(stderr, "ouch: freeing free people (from %s:%d)\n",
294 : : file, line);
295 : : die();
296 : : }
297 : : mem[i].block = 0;
298 : : freemem_raw(y);
299 : : }
300 : :
301 : : void *incmem_debug(void *x, size_t ol, size_t nl, char *file, int line)
302 : : {
303 : : void *y = getmem_debug(nl, file, line);
304 : : mmv(y, x, ol < nl ? ol : nl);
305 : : freemem_debug(x, file, line);
306 : : return y;
307 : : }
308 : :
309 : : char *sdup_debug(char *src, char *file, int line)
310 : : {
311 : : size_t n = 1 + strlen(src);
312 : : char *x = getmem_debug(n, file, line);
313 : :
314 : : mmv(x, src, n);
315 : : return x;
316 : : }
317 : :
318 : : void report_leaks(void)
319 : : {
320 : : size_t i;
321 : :
322 : : for (i = 0; i < meml; i ++) {
323 : : if (mem[i].block) fprintf(stderr, "leak: serial %ld, %s:%d\n",
324 : : mem[i].serial, mem[i].file, mem[i].line);
325 : : }
326 : : }
327 : :
328 : : #endif
|