/* Mudflap: narrow-pointer bounds-checking by tree rewriting. Copyright (C) 2002, 2003 Free Software Foundation, Inc. Contributed by Frank Ch. Eigler and Graydon Hoare This file is part of GCC. XXX: libgcc license? */ #include "config.h" #ifndef HAVE_SOCKLEN_T #define socklen_t int #endif /* These attempt to coax various unix flavours to declare all our needed tidbits in the system headers. */ #if !defined(__FreeBSD__) && !defined(__APPLE__) #define _POSIX_SOURCE #endif /* Some BSDs break if this is defined. */ #define _GNU_SOURCE #define _XOPEN_SOURCE #define _BSD_TYPES #define __EXTENSIONS__ #define _ALL_SOURCE #define _LARGE_FILE_API #define _XOPEN_SOURCE_EXTENDED 1 #include #include #include #include #include #include #include #include #include #include #include "mf-runtime.h" #include "mf-impl.h" #ifdef _MUDFLAP #error "Do not compile this file with -fmudflap!" #endif /* Memory allocation related hook functions. Some of these are intercepted via linker wrapping or symbol interposition. Others use plain macros in mf-runtime.h. */ #ifdef WRAP_malloc #if PIC /* A special bootstrap variant. */ void * __mf_0fn_malloc (size_t c) { /* fprintf (stderr, "0fn malloc c=%lu\n", c); */ return NULL; } #endif #undef malloc WRAPPER(void *, malloc, size_t c) { size_t size_with_crumple_zones; DECLARE(void *, malloc, size_t c); void *result; BEGIN_PROTECT (malloc, c); size_with_crumple_zones = CLAMPADD(c,CLAMPADD(__mf_opts.crumple_zone, __mf_opts.crumple_zone)); result = (char *) CALL_REAL (malloc, size_with_crumple_zones); if (LIKELY(result)) { result += __mf_opts.crumple_zone; __mf_register (result, c, __MF_TYPE_HEAP, "malloc region"); /* XXX: register __MF_TYPE_NOACCESS for crumple zones. */ } return result; } #endif #ifdef WRAP_calloc #ifdef PIC /* A special bootstrap variant. */ void * __mf_0fn_calloc (size_t c, size_t n) { enum foo { BS = 4096, NB=10 }; static char bufs[NB][BS]; static unsigned bufs_used[NB]; unsigned i; /* fprintf (stderr, "0fn calloc c=%lu n=%lu\n", c, n); */ for (i=0; i 0)) { char *freeme = NULL; LOCKTH (); if (free_queue [free_ptr] != NULL) { freeme = free_queue [free_ptr]; freeme -= __mf_opts.crumple_zone; } free_queue [free_ptr] = buf; free_ptr = (free_ptr == (__mf_opts.free_queue_length-1) ? 0 : free_ptr + 1); UNLOCKTH (); if (freeme) { if (__mf_opts.trace_mf_calls) { VERBOSE_TRACE ("freeing deferred pointer %p (crumple %u)\n", (void *) freeme, __mf_opts.crumple_zone); } CALL_REAL (free, freeme); } } else { /* back pointer up a bit to the beginning of crumple zone */ char *base = (char *)buf; base -= __mf_opts.crumple_zone; if (__mf_opts.trace_mf_calls) { VERBOSE_TRACE ("freeing pointer %p = %p - %u\n", (void *) base, (void *) buf, __mf_opts.crumple_zone); } CALL_REAL (free, base); } } #endif #ifdef WRAP_mmap #if PIC /* A special bootstrap variant. */ void * __mf_0fn_mmap (void *start, size_t l, int prot, int f, int fd, off_t off) { return (void *) -1; } #endif #undef mmap WRAPPER(void *, mmap, void *start, size_t length, int prot, int flags, int fd, off_t offset) { DECLARE(void *, mmap, void *, size_t, int, int, int, off_t); void *result; BEGIN_PROTECT (mmap, start, length, prot, flags, fd, offset); result = CALL_REAL (mmap, start, length, prot, flags, fd, offset); /* VERBOSE_TRACE ("mmap (%08lx, %08lx, ...) => %08lx\n", (uintptr_t) start, (uintptr_t) length, (uintptr_t) result); */ if (result != (void *)-1) { /* Register each page as a heap object. Why not register it all as a single segment? That's so that a later munmap() call can unmap individual pages. XXX: would __MF_TYPE_GUESS make this more automatic? */ size_t ps = getpagesize (); uintptr_t base = (uintptr_t) result; uintptr_t offset; for (offset=0; offset %08lx\n", (uintptr_t) start, (uintptr_t) length, (uintptr_t) result); */ if (result == 0) { /* Unregister each page as a heap object. */ size_t ps = getpagesize (); uintptr_t base = (uintptr_t) start & (~ (ps - 1)); /* page align */ uintptr_t offset; for (offset=0; offsetstack DEEPER_THAN (uintptr_t) stack)) { struct alloca_tracking *next = alloca_history->next; __mf_unregister (alloca_history->ptr, 0); CALL_REAL (free, alloca_history->ptr); CALL_REAL (free, alloca_history); alloca_history = next; } /* Allocate new block. */ result = NULL; if (LIKELY (c > 0)) /* alloca(0) causes no allocation. */ { track = (struct alloca_tracking *) CALL_REAL (malloc, sizeof (struct alloca_tracking)); if (LIKELY (track != NULL)) { result = CALL_REAL (malloc, c); if (UNLIKELY (result == NULL)) { CALL_REAL (free, track); /* Too bad. XXX: What about errno? */ } else { __mf_register (result, c, __MF_TYPE_HEAP, "alloca region"); track->ptr = result; track->stack = stack; track->next = alloca_history; alloca_history = track; } } } return result; } #undef alloca WRAPPER(void *, alloca, size_t c) { return __mf_wrap_alloca_indirect (c); } #endif