asan_globals.cc revision 1e172b4bdec57329bf904f063a29f99cddf2d85f
1f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//===-- asan_globals.cc -----------------------------------------*- C++ -*-===//
2f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//
3f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//                     The LLVM Compiler Infrastructure
4f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//
5f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// This file is distributed under the University of Illinois Open Source
6f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// License. See LICENSE.TXT for details.
7f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//
8f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//===----------------------------------------------------------------------===//
9f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//
10f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// This file is a part of AddressSanitizer, an address sanity checker.
11f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//
123f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org// Handle globals.
13f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com//===----------------------------------------------------------------------===//
14f47223d0c72e105acf8247446ba94255467dff77kjellander@webrtc.org#include "asan_interceptors.h"
15f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include "asan_interface.h"
16cff5c03bbf63004ab85478a5660d341d3366ef63pbos@webrtc.org#include "asan_internal.h"
17f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include "asan_lock.h"
18f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include "asan_mapping.h"
19f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include "asan_stack.h"
20f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include "asan_stats.h"
21f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include "asan_thread.h"
22f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
23f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include <ctype.h>
24f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com#include <map>
25f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
26f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comnamespace __asan {
27f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
28f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comtypedef __asan_global Global;
29f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
30f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comstatic AsanLock mu_for_globals(LINKER_INITIALIZED);
31f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comtypedef std::map<uintptr_t, Global> MapOfGlobals;
329f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.orgstatic MapOfGlobals *g_all_globals = NULL;
339f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org
349f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.orgvoid PoisonRedZones(const Global &g)  {
359f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  uintptr_t shadow = MemToShadow(g.beg);
36f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  size_t ShadowRZSize = kGlobalAndStackRedzone >> SHADOW_SCALE;
37f47223d0c72e105acf8247446ba94255467dff77kjellander@webrtc.org  CHECK(ShadowRZSize == 1 || ShadowRZSize == 2 || ShadowRZSize == 4);
38f47223d0c72e105acf8247446ba94255467dff77kjellander@webrtc.org  // full right redzone
399f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  uintptr_t right_rz2_offset = ShadowRZSize *
40f47223d0c72e105acf8247446ba94255467dff77kjellander@webrtc.org      ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
41f47223d0c72e105acf8247446ba94255467dff77kjellander@webrtc.org  real_memset((uint8_t*)shadow + right_rz2_offset,
42f47223d0c72e105acf8247446ba94255467dff77kjellander@webrtc.org              kAsanGlobalRedzoneMagic, ShadowRZSize);
439f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  if ((g.size % kGlobalAndStackRedzone) != 0) {
44f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    // partial right redzone
45f47223d0c72e105acf8247446ba94255467dff77kjellander@webrtc.org    uint64_t right_rz1_offset =
46f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com        ShadowRZSize * (g.size / kGlobalAndStackRedzone);
47f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    CHECK(right_rz1_offset == right_rz2_offset - ShadowRZSize);
48f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    PoisonShadowPartialRightRedzone((uint8_t*)(shadow + right_rz1_offset),
49f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com                                    g.size % kGlobalAndStackRedzone,
50f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com                                    kGlobalAndStackRedzone,
51f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com                                    SHADOW_GRANULARITY,
52f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com                                    kAsanGlobalRedzoneMagic);
53f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  }
54f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
55f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
56ba47616ee5a8d8a4d94e160b64b79a56845e291bandrew@webrtc.orgstatic size_t GetAlignedSize(size_t size) {
57ba47616ee5a8d8a4d94e160b64b79a56845e291bandrew@webrtc.org  return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
58f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com      * kGlobalAndStackRedzone;
59f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
60f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
61f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  // Check if the global is a zero-terminated ASCII string. If so, print it.
62f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comvoid PrintIfASCII(const Global &g) {
63f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  for (size_t p = g.beg; p < g.beg + g.size - 1; p++) {
64f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    if (!isascii(*(char*)p)) return;
65f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  }
66f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (*(char*)(g.beg + g.size - 1) != 0) return;
67f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  Printf("  '%s' is ascii string '%s'\n", g.name, g.beg);
68f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
69f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
70f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.combool DescribeAddrIfMyRedZone(const Global &g, uintptr_t addr) {
71f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (addr < g.beg - kGlobalAndStackRedzone) return false;
72f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (addr >= g.beg + g.size_with_redzone) return false;
73f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  Printf("%p is located ", addr);
74f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (addr < g.beg) {
75f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    Printf("%d bytes to the left", g.beg - addr);
769f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  } else if (addr >= g.beg + g.size) {
779f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org    Printf("%d bytes to the right", addr - (g.beg + g.size));
78f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  } else {
79f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    Printf("%d bytes inside", addr - g.beg);  // Can it happen?
80f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  }
81ba47616ee5a8d8a4d94e160b64b79a56845e291bandrew@webrtc.org  Printf(" of global variable '%s' (0x%lx) of size %ld\n",
82ba47616ee5a8d8a4d94e160b64b79a56845e291bandrew@webrtc.org         g.name, g.beg, g.size);
83f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  PrintIfASCII(g);
84f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  return true;
85f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
86f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
87f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
88f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.combool DescribeAddrIfGlobal(uintptr_t addr) {
89f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (!FLAG_report_globals) return false;
90f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  ScopedLock lock(&mu_for_globals);
919f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  if (!g_all_globals) return false;
929f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  bool res = false;
939f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  // Just iterate. May want to use binary search instead.
94f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  for (MapOfGlobals::iterator i = g_all_globals->begin(),
95f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com       end = g_all_globals->end(); i != end; ++i) {
96f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    Global &g = i->second;
97f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    CHECK(i->first == g.beg);
98f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    if (FLAG_report_globals >= 2)
99f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com      Printf("Search Global: beg=%p size=%ld name=%s\n",
100f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com             g.beg, g.size, g.name);
101f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    res |= DescribeAddrIfMyRedZone(g, addr);
102f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  }
103f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  return res;
104f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
105f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
106f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// Register a global variable.
107f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// This function may be called more than once for every global
108f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// so we store the globals in a map.
109f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comstatic void RegisterGlobal(const Global *g) {
110f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  CHECK(asan_inited);
111f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (!FLAG_report_globals) return;
112f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  ScopedLock lock(&mu_for_globals);
113f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (!g_all_globals)
114f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    g_all_globals = new MapOfGlobals;
115f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  CHECK(AddrIsInMem(g->beg));
116f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  if (FLAG_report_globals >= 2)
117f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    Printf("Added Global: beg=%p size=%ld name=%s\n",
118f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com           g->beg, g->size, g->name);
119f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  PoisonRedZones(*g);
120f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  (*g_all_globals)[g->beg] = *g;
121f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
1229f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org
1239f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org}  // namespace __asan
1249f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org
125f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// ---------------------- Interface ---------------- {{{1
126f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comusing namespace __asan;  // NOLINT
127f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
128f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// Register one global with a default redzone.
1299f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.orgvoid __asan_register_global(uintptr_t addr, size_t size,
130f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com                            const char *name) {
131f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  Global g;
132f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  g.beg = addr;
133f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  g.size = size;
134f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  g.size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone;
1359f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  g.name = name;
1369f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org  RegisterGlobal(&g);
137f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
138f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com
139f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com// Register an array of globals.
140f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.comvoid __asan_register_globals(__asan_global *globals, size_t n) {
141f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  for (size_t i = 0; i < n; i++) {
142f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com    RegisterGlobal(&globals[i]);
143f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com  }
144f8b1da2faffe818a2d85e8904d2c4f09e5db4d5cbrykt@google.com}
1459f4ae03d99cc213b797f49afb737a7a4fe98454ckjellander@webrtc.org