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 0 : 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 0 : 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 0 : 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 0 : char *(sdup)(char *src)
170 : {
171 0 : size_t n = 1 + strlen(src);
172 0 : char *x = getmem(n);
173 :
174 0 : mmv(x, src, n);
175 0 : 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
|