/* Mudflap: narrow-pointer bounds-checking by tree rewriting. Copyright (C) 2002-2013 Free Software Foundation, Inc. Contributed by Frank Ch. Eigler and Graydon Hoare This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ #include "config.h" #include #include "mf-runtime.h" #include "mf-impl.h" #ifdef _MUDFLAP #error "Do not compile this file with -fmudflap!" #endif extern char _end[]; extern char ENTRY_POINT[]; /* Run some quick validation of the given region. Return -1 / 0 / 1 if the access known-invalid, possibly-valid, or known-valid. */ int __mf_heuristic_check (uintptr_t ptr, uintptr_t ptr_high) { VERBOSE_TRACE ("mf: heuristic check\n"); /* XXX: Disable the stack bounding check for libmudflapth. We do actually have enough information to track stack bounds (see __mf_pthread_info in mf-hooks.c), so with a bit of future work, this heuristic can be turned on. */ #ifndef LIBMUDFLAPTH /* The first heuristic is to check stack bounds. This is a transient condition and quick to check. */ if (__mf_opts.heur_stack_bound) { uintptr_t stack_top_guess = (uintptr_t)__builtin_frame_address(0); #if defined(__i386__) && defined (__linux__) uintptr_t stack_segment_base = 0xC0000000; /* XXX: Bad assumption. */ #else /* Cause tests to fail. */ uintptr_t stack_segment_base = 0; #endif VERBOSE_TRACE ("mf: stack estimated as %p-%p\n", (void *) stack_top_guess, (void *) stack_segment_base); if (ptr_high <= stack_segment_base && ptr >= stack_top_guess && ptr_high >= ptr) { return 1; } } #endif /* The second heuristic is to scan the range of memory regions listed in /proc/self/maps, a special file provided by the Linux kernel. Its results may be cached, and in fact, a GUESS object may as well be recorded for interesting matching sections. */ if (__mf_opts.heur_proc_map) { /* Keep a record of seen records from /proc/self/map. */ enum { max_entries = 500 }; struct proc_self_map_entry { uintptr_t low; uintptr_t high; }; static struct proc_self_map_entry entry [max_entries]; static unsigned entry_used [max_entries]; /* Look for a known proc_self_map entry that may cover this region. If one exists, then this heuristic has already run, and should not be run again. The check should be allowed to fail. */ unsigned i; unsigned deja_vu = 0; for (i=0; i= ptr_high)) deja_vu = 1; } if (! deja_vu) { /* Time to run the heuristic. Rescan /proc/self/maps; update the entry[] array; XXX: remove expired entries, add new ones. XXX: Consider entries that have grown (e.g., stack). */ char buf[512]; char flags[4]; void *low, *high; FILE *fp; fp = fopen ("/proc/self/maps", "r"); if (fp) { while (fgets (buf, sizeof(buf), fp)) { if (sscanf (buf, "%p-%p %4c", &low, &high, flags) == 3) { if ((uintptr_t) low <= ptr && (uintptr_t) high >= ptr_high) { for (i=0; i= (uintptr_t) & ENTRY_POINT && ptr_high <= (uintptr_t) & _end) return 1; /* uncacheable */ return 0; /* unknown */ }