PR middle-end/23971
[official-gcc.git] / libmudflap / mf-hooks1.c
bloba99d7726e9da119cdd222bfcd283577cc71c64e3
1 /* Mudflap: narrow-pointer bounds-checking by tree rewriting.
2 Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Frank Ch. Eigler <fche@redhat.com>
4 and Graydon Hoare <graydon@redhat.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file. (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
20 executable.)
22 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
23 WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 for more details.
27 You should have received a copy of the GNU General Public License
28 along with GCC; see the file COPYING. If not, write to the Free
29 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30 02110-1301, USA. */
33 #include "config.h"
35 #ifndef HAVE_SOCKLEN_T
36 #define socklen_t int
37 #endif
40 /* These attempt to coax various unix flavours to declare all our
41 needed tidbits in the system headers. */
42 #if !defined(__FreeBSD__) && !defined(__APPLE__)
43 #define _POSIX_SOURCE
44 #endif /* Some BSDs break <sys/socket.h> if this is defined. */
45 #define _GNU_SOURCE
46 #define _XOPEN_SOURCE
47 #define _BSD_TYPES
48 #define __EXTENSIONS__
49 #define _ALL_SOURCE
50 #define _LARGE_FILE_API
51 #define _XOPEN_SOURCE_EXTENDED 1
53 #include <string.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <unistd.h>
59 #include <assert.h>
60 #include <errno.h>
61 #include <limits.h>
62 #include <time.h>
64 #include "mf-runtime.h"
65 #include "mf-impl.h"
67 #ifdef _MUDFLAP
68 #error "Do not compile this file with -fmudflap!"
69 #endif
72 /* Memory allocation related hook functions. Some of these are
73 intercepted via linker wrapping or symbol interposition. Others
74 use plain macros in mf-runtime.h. */
77 #if PIC
78 /* A special bootstrap variant. */
79 void *
80 __mf_0fn_malloc (size_t c)
82 enum foo { BS = 4096, NB=10 };
83 static char bufs[NB][BS];
84 static unsigned bufs_used[NB];
85 unsigned i;
87 for (i=0; i<NB; i++)
89 if (! bufs_used[i] && c < BS)
91 bufs_used[i] = 1;
92 return & bufs[i][0];
95 return NULL;
97 #endif
100 #undef malloc
101 WRAPPER(void *, malloc, size_t c)
103 size_t size_with_crumple_zones;
104 DECLARE(void *, malloc, size_t c);
105 void *result;
106 BEGIN_PROTECT (malloc, c);
108 size_with_crumple_zones =
109 CLAMPADD(c,CLAMPADD(__mf_opts.crumple_zone,
110 __mf_opts.crumple_zone));
111 BEGIN_MALLOC_PROTECT ();
112 result = (char *) CALL_REAL (malloc, size_with_crumple_zones);
113 END_MALLOC_PROTECT ();
115 if (LIKELY(result))
117 result += __mf_opts.crumple_zone;
118 __mf_register (result, c, __MF_TYPE_HEAP, "malloc region");
119 /* XXX: register __MF_TYPE_NOACCESS for crumple zones. */
122 return result;
126 #ifdef PIC
127 /* A special bootstrap variant. */
128 void *
129 __mf_0fn_calloc (size_t c, size_t n)
131 return __mf_0fn_malloc (c * n);
133 #endif
136 #undef calloc
137 WRAPPER(void *, calloc, size_t c, size_t n)
139 size_t size_with_crumple_zones;
140 DECLARE(void *, calloc, size_t, size_t);
141 DECLARE(void *, malloc, size_t);
142 DECLARE(void *, memset, void *, int, size_t);
143 char *result;
144 BEGIN_PROTECT (calloc, c, n);
146 size_with_crumple_zones =
147 CLAMPADD((c * n), /* XXX: CLAMPMUL */
148 CLAMPADD(__mf_opts.crumple_zone,
149 __mf_opts.crumple_zone));
150 BEGIN_MALLOC_PROTECT ();
151 result = (char *) CALL_REAL (malloc, size_with_crumple_zones);
152 END_MALLOC_PROTECT ();
154 if (LIKELY(result))
155 memset (result, 0, size_with_crumple_zones);
157 if (LIKELY(result))
159 result += __mf_opts.crumple_zone;
160 __mf_register (result, c*n /* XXX: clamp */, __MF_TYPE_HEAP_I, "calloc region");
161 /* XXX: register __MF_TYPE_NOACCESS for crumple zones. */
164 return result;
168 #if PIC
169 /* A special bootstrap variant. */
170 void *
171 __mf_0fn_realloc (void *buf, size_t c)
173 return NULL;
175 #endif
178 #undef realloc
179 WRAPPER(void *, realloc, void *buf, size_t c)
181 DECLARE(void * , realloc, void *, size_t);
182 size_t size_with_crumple_zones;
183 char *base = buf;
184 unsigned saved_wipe_heap;
185 char *result;
186 BEGIN_PROTECT (realloc, buf, c);
188 if (LIKELY(buf))
189 base -= __mf_opts.crumple_zone;
191 size_with_crumple_zones =
192 CLAMPADD(c, CLAMPADD(__mf_opts.crumple_zone,
193 __mf_opts.crumple_zone));
194 BEGIN_MALLOC_PROTECT ();
195 result = (char *) CALL_REAL (realloc, base, size_with_crumple_zones);
196 END_MALLOC_PROTECT ();
198 /* Ensure heap wiping doesn't occur during this peculiar
199 unregister/reregister pair. */
200 LOCKTH ();
201 __mf_set_state (reentrant);
202 saved_wipe_heap = __mf_opts.wipe_heap;
203 __mf_opts.wipe_heap = 0;
205 if (LIKELY(buf))
206 __mfu_unregister (buf, 0, __MF_TYPE_HEAP_I);
207 /* NB: underlying region may have been __MF_TYPE_HEAP. */
209 if (LIKELY(result))
211 result += __mf_opts.crumple_zone;
212 __mfu_register (result, c, __MF_TYPE_HEAP_I, "realloc region");
213 /* XXX: register __MF_TYPE_NOACCESS for crumple zones. */
216 /* Restore previous setting. */
217 __mf_opts.wipe_heap = saved_wipe_heap;
219 __mf_set_state (active);
220 UNLOCKTH ();
222 return result;
226 #if PIC
227 /* A special bootstrap variant. */
228 void
229 __mf_0fn_free (void *buf)
231 return;
233 #endif
235 #undef free
236 WRAPPER(void, free, void *buf)
238 /* Use a circular queue to delay some number (__mf_opts.free_queue_length) of free()s. */
239 static void *free_queue [__MF_FREEQ_MAX];
240 static unsigned free_ptr = 0;
241 static int freeq_initialized = 0;
242 DECLARE(void, free, void *);
244 BEGIN_PROTECT (free, buf);
246 if (UNLIKELY(buf == NULL))
247 return;
249 LOCKTH ();
250 if (UNLIKELY(!freeq_initialized))
252 memset (free_queue, 0,
253 __MF_FREEQ_MAX * sizeof (void *));
254 freeq_initialized = 1;
256 UNLOCKTH ();
258 __mf_unregister (buf, 0, __MF_TYPE_HEAP_I);
259 /* NB: underlying region may have been __MF_TYPE_HEAP. */
261 if (UNLIKELY(__mf_opts.free_queue_length > 0))
263 char *freeme = NULL;
264 LOCKTH ();
265 if (free_queue [free_ptr] != NULL)
267 freeme = free_queue [free_ptr];
268 freeme -= __mf_opts.crumple_zone;
270 free_queue [free_ptr] = buf;
271 free_ptr = (free_ptr == (__mf_opts.free_queue_length-1) ? 0 : free_ptr + 1);
272 UNLOCKTH ();
273 if (freeme)
275 if (__mf_opts.trace_mf_calls)
277 VERBOSE_TRACE ("freeing deferred pointer %p (crumple %u)\n",
278 (void *) freeme,
279 __mf_opts.crumple_zone);
281 BEGIN_MALLOC_PROTECT ();
282 CALL_REAL (free, freeme);
283 END_MALLOC_PROTECT ();
286 else
288 /* back pointer up a bit to the beginning of crumple zone */
289 char *base = (char *)buf;
290 base -= __mf_opts.crumple_zone;
291 if (__mf_opts.trace_mf_calls)
293 VERBOSE_TRACE ("freeing pointer %p = %p - %u\n",
294 (void *) base,
295 (void *) buf,
296 __mf_opts.crumple_zone);
298 BEGIN_MALLOC_PROTECT ();
299 CALL_REAL (free, base);
300 END_MALLOC_PROTECT ();
305 #if PIC
306 /* A special bootstrap variant. */
307 void *
308 __mf_0fn_mmap (void *start, size_t l, int prot, int f, int fd, off_t off)
310 return (void *) -1;
312 #endif
315 #undef mmap
316 WRAPPER(void *, mmap,
317 void *start, size_t length, int prot,
318 int flags, int fd, off_t offset)
320 DECLARE(void *, mmap, void *, size_t, int,
321 int, int, off_t);
322 void *result;
323 BEGIN_PROTECT (mmap, start, length, prot, flags, fd, offset);
325 result = CALL_REAL (mmap, start, length, prot,
326 flags, fd, offset);
329 VERBOSE_TRACE ("mmap (%08lx, %08lx, ...) => %08lx\n",
330 (uintptr_t) start, (uintptr_t) length,
331 (uintptr_t) result);
334 if (result != (void *)-1)
336 /* Register each page as a heap object. Why not register it all
337 as a single segment? That's so that a later munmap() call
338 can unmap individual pages. XXX: would __MF_TYPE_GUESS make
339 this more automatic? */
340 size_t ps = getpagesize ();
341 uintptr_t base = (uintptr_t) result;
342 uintptr_t offset;
344 for (offset=0; offset<length; offset+=ps)
346 /* XXX: We could map PROT_NONE to __MF_TYPE_NOACCESS. */
347 /* XXX: Unaccessed HEAP pages are reported as leaks. Is this
348 appropriate for unaccessed mmap pages? */
349 __mf_register ((void *) CLAMPADD (base, offset), ps,
350 __MF_TYPE_HEAP_I, "mmap page");
354 return result;
358 #if PIC
359 /* A special bootstrap variant. */
361 __mf_0fn_munmap (void *start, size_t length)
363 return -1;
365 #endif
368 #undef munmap
369 WRAPPER(int , munmap, void *start, size_t length)
371 DECLARE(int, munmap, void *, size_t);
372 int result;
373 BEGIN_PROTECT (munmap, start, length);
375 result = CALL_REAL (munmap, start, length);
378 VERBOSE_TRACE ("munmap (%08lx, %08lx, ...) => %08lx\n",
379 (uintptr_t) start, (uintptr_t) length,
380 (uintptr_t) result);
383 if (result == 0)
385 /* Unregister each page as a heap object. */
386 size_t ps = getpagesize ();
387 uintptr_t base = (uintptr_t) start & (~ (ps - 1)); /* page align */
388 uintptr_t offset;
390 for (offset=0; offset<length; offset+=ps)
391 __mf_unregister ((void *) CLAMPADD (base, offset), ps, __MF_TYPE_HEAP_I);
393 return result;
397 /* This wrapper is a little different, as it's called indirectly from
398 __mf_fini also to clean up pending allocations. */
399 void *
400 __mf_wrap_alloca_indirect (size_t c)
402 DECLARE (void *, malloc, size_t);
403 DECLARE (void, free, void *);
405 /* This struct, a linked list, tracks alloca'd objects. The newest
406 object is at the head of the list. If we detect that we've
407 popped a few levels of stack, then the listed objects are freed
408 as needed. NB: The tracking struct is allocated with
409 real_malloc; the user data with wrap_malloc.
411 struct alloca_tracking { void *ptr; void *stack; struct alloca_tracking* next; };
412 static struct alloca_tracking *alloca_history = NULL;
414 void *stack = __builtin_frame_address (0);
415 void *result;
416 struct alloca_tracking *track;
418 TRACE ("%s\n", __PRETTY_FUNCTION__);
419 VERBOSE_TRACE ("alloca stack level %p\n", (void *) stack);
421 /* XXX: thread locking! */
423 /* Free any previously alloca'd blocks that belong to deeper-nested functions,
424 which must therefore have exited by now. */
426 #define DEEPER_THAN < /* XXX: for x86; steal find_stack_direction() from libiberty/alloca.c */
428 while (alloca_history &&
429 ((uintptr_t) alloca_history->stack DEEPER_THAN (uintptr_t) stack))
431 struct alloca_tracking *next = alloca_history->next;
432 __mf_unregister (alloca_history->ptr, 0, __MF_TYPE_HEAP);
433 BEGIN_MALLOC_PROTECT ();
434 CALL_REAL (free, alloca_history->ptr);
435 CALL_REAL (free, alloca_history);
436 END_MALLOC_PROTECT ();
437 alloca_history = next;
440 /* Allocate new block. */
441 result = NULL;
442 if (LIKELY (c > 0)) /* alloca(0) causes no allocation. */
444 BEGIN_MALLOC_PROTECT ();
445 track = (struct alloca_tracking *) CALL_REAL (malloc,
446 sizeof (struct alloca_tracking));
447 END_MALLOC_PROTECT ();
448 if (LIKELY (track != NULL))
450 BEGIN_MALLOC_PROTECT ();
451 result = CALL_REAL (malloc, c);
452 END_MALLOC_PROTECT ();
453 if (UNLIKELY (result == NULL))
455 BEGIN_MALLOC_PROTECT ();
456 CALL_REAL (free, track);
457 END_MALLOC_PROTECT ();
458 /* Too bad. XXX: What about errno? */
460 else
462 __mf_register (result, c, __MF_TYPE_HEAP, "alloca region");
463 track->ptr = result;
464 track->stack = stack;
465 track->next = alloca_history;
466 alloca_history = track;
471 return result;
475 #undef alloca
476 WRAPPER(void *, alloca, size_t c)
478 return __mf_wrap_alloca_indirect (c);