diff options
author | Kostya Serebryany <kcc@google.com> | 2011-11-30 01:07:02 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@google.com> | 2011-11-30 01:07:02 +0000 |
commit | 1e172b4bdec57329bf904f063a29f99cddf2d85f (patch) | |
tree | 615823ee9e1c1dfa52262cbf608c8e63cd07d0f3 /lib/asan/asan_globals.cc | |
parent | 1626d864159d42d1c5a492c1cb686f629e81f815 (diff) |
AddressSanitizer run-time library. Not yet integrated with the compiler-rt build system, but can be built using the old makefile. See details in README.txt
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@145463 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/asan/asan_globals.cc')
-rw-r--r-- | lib/asan/asan_globals.cc | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc new file mode 100644 index 000000000..ab4a10c64 --- /dev/null +++ b/lib/asan/asan_globals.cc @@ -0,0 +1,144 @@ +//===-- asan_globals.cc -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Handle globals. +//===----------------------------------------------------------------------===// +#include "asan_interceptors.h" +#include "asan_interface.h" +#include "asan_internal.h" +#include "asan_lock.h" +#include "asan_mapping.h" +#include "asan_stack.h" +#include "asan_stats.h" +#include "asan_thread.h" + +#include <ctype.h> +#include <map> + +namespace __asan { + +typedef __asan_global Global; + +static AsanLock mu_for_globals(LINKER_INITIALIZED); +typedef std::map<uintptr_t, Global> MapOfGlobals; +static MapOfGlobals *g_all_globals = NULL; + +void PoisonRedZones(const Global &g) { + uintptr_t shadow = MemToShadow(g.beg); + size_t ShadowRZSize = kGlobalAndStackRedzone >> SHADOW_SCALE; + CHECK(ShadowRZSize == 1 || ShadowRZSize == 2 || ShadowRZSize == 4); + // full right redzone + uintptr_t right_rz2_offset = ShadowRZSize * + ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone); + real_memset((uint8_t*)shadow + right_rz2_offset, + kAsanGlobalRedzoneMagic, ShadowRZSize); + if ((g.size % kGlobalAndStackRedzone) != 0) { + // partial right redzone + uint64_t right_rz1_offset = + ShadowRZSize * (g.size / kGlobalAndStackRedzone); + CHECK(right_rz1_offset == right_rz2_offset - ShadowRZSize); + PoisonShadowPartialRightRedzone((uint8_t*)(shadow + right_rz1_offset), + g.size % kGlobalAndStackRedzone, + kGlobalAndStackRedzone, + SHADOW_GRANULARITY, + kAsanGlobalRedzoneMagic); + } +} + +static size_t GetAlignedSize(size_t size) { + return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone) + * kGlobalAndStackRedzone; +} + + // Check if the global is a zero-terminated ASCII string. If so, print it. +void PrintIfASCII(const Global &g) { + for (size_t p = g.beg; p < g.beg + g.size - 1; p++) { + if (!isascii(*(char*)p)) return; + } + if (*(char*)(g.beg + g.size - 1) != 0) return; + Printf(" '%s' is ascii string '%s'\n", g.name, g.beg); +} + +bool DescribeAddrIfMyRedZone(const Global &g, uintptr_t addr) { + if (addr < g.beg - kGlobalAndStackRedzone) return false; + if (addr >= g.beg + g.size_with_redzone) return false; + Printf("%p is located ", addr); + if (addr < g.beg) { + Printf("%d bytes to the left", g.beg - addr); + } else if (addr >= g.beg + g.size) { + Printf("%d bytes to the right", addr - (g.beg + g.size)); + } else { + Printf("%d bytes inside", addr - g.beg); // Can it happen? + } + Printf(" of global variable '%s' (0x%lx) of size %ld\n", + g.name, g.beg, g.size); + PrintIfASCII(g); + return true; +} + + +bool DescribeAddrIfGlobal(uintptr_t addr) { + if (!FLAG_report_globals) return false; + ScopedLock lock(&mu_for_globals); + if (!g_all_globals) return false; + bool res = false; + // Just iterate. May want to use binary search instead. + for (MapOfGlobals::iterator i = g_all_globals->begin(), + end = g_all_globals->end(); i != end; ++i) { + Global &g = i->second; + CHECK(i->first == g.beg); + if (FLAG_report_globals >= 2) + Printf("Search Global: beg=%p size=%ld name=%s\n", + g.beg, g.size, g.name); + res |= DescribeAddrIfMyRedZone(g, addr); + } + return res; +} + +// Register a global variable. +// This function may be called more than once for every global +// so we store the globals in a map. +static void RegisterGlobal(const Global *g) { + CHECK(asan_inited); + if (!FLAG_report_globals) return; + ScopedLock lock(&mu_for_globals); + if (!g_all_globals) + g_all_globals = new MapOfGlobals; + CHECK(AddrIsInMem(g->beg)); + if (FLAG_report_globals >= 2) + Printf("Added Global: beg=%p size=%ld name=%s\n", + g->beg, g->size, g->name); + PoisonRedZones(*g); + (*g_all_globals)[g->beg] = *g; +} + +} // namespace __asan + +// ---------------------- Interface ---------------- {{{1 +using namespace __asan; // NOLINT + +// Register one global with a default redzone. +void __asan_register_global(uintptr_t addr, size_t size, + const char *name) { + Global g; + g.beg = addr; + g.size = size; + g.size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone; + g.name = name; + RegisterGlobal(&g); +} + +// Register an array of globals. +void __asan_register_globals(__asan_global *globals, size_t n) { + for (size_t i = 0; i < n; i++) { + RegisterGlobal(&globals[i]); + } +} |