blob: 3c3d620c62ad2fd92bbb31a8118191807bdea564 [file] [log] [blame]
Alexey Samsonove5f58952012-06-04 13:50:10 +00001//===-- asan_globals.cc ---------------------------------------------------===//
Kostya Serebryany1e172b42011-11-30 01:07:02 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Handle globals.
13//===----------------------------------------------------------------------===//
14#include "asan_interceptors.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000015#include "asan_internal.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000016#include "asan_mapping.h"
Alexey Samsonov7e843492013-03-28 15:42:43 +000017#include "asan_poisoning.h"
Alexey Samsonove4bfca22012-08-09 09:27:24 +000018#include "asan_report.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000019#include "asan_stack.h"
20#include "asan_stats.h"
21#include "asan_thread.h"
Alexey Samsonov7e843492013-03-28 15:42:43 +000022#include "sanitizer_common/sanitizer_common.h"
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +000023#include "sanitizer_common/sanitizer_mutex.h"
Alexey Samsonov7e843492013-03-28 15:42:43 +000024#include "sanitizer_common/sanitizer_placement_new.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000025
Kostya Serebryany1e172b42011-11-30 01:07:02 +000026namespace __asan {
27
28typedef __asan_global Global;
29
Kostya Serebryanyb89567c2011-12-02 21:02:20 +000030struct ListOfGlobals {
31 const Global *g;
32 ListOfGlobals *next;
33};
34
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +000035static BlockingMutex mu_for_globals(LINKER_INITIALIZED);
Alexey Samsonov947fbd12012-08-27 14:04:54 +000036static LowLevelAllocator allocator_for_globals;
Kostya Serebryany3945c582012-08-21 14:10:25 +000037static ListOfGlobals *list_of_all_globals;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000038
Alexey Samsonov7e843492013-03-28 15:42:43 +000039static const int kDynamicInitGlobalsInitialCapacity = 512;
Alexey Samsonovdfeef672013-04-19 08:35:16 +000040struct DynInitGlobal {
41 Global g;
42 bool initialized;
43};
Alexey Samsonova64d4352013-06-14 09:59:40 +000044typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
Alexey Samsonov7e843492013-03-28 15:42:43 +000045// Lazy-initialized and never deleted.
46static VectorOfGlobals *dynamic_init_globals;
47
Timur Iskhodzhanovabfdbdf2013-03-28 18:52:40 +000048ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
Alexey Samsonov7e843492013-03-28 15:42:43 +000049 FastPoisonShadow(g->beg, g->size_with_redzone, value);
50}
51
Timur Iskhodzhanovabfdbdf2013-03-28 18:52:40 +000052ALWAYS_INLINE void PoisonRedZones(const Global &g) {
Kostya Serebryanya3b0e5e2013-01-23 11:14:21 +000053 uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
Alexey Samsonov7e843492013-03-28 15:42:43 +000054 FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
55 kAsanGlobalRedzoneMagic);
Kostya Serebryanya3b0e5e2013-01-23 11:14:21 +000056 if (g.size != aligned_size) {
Alexey Samsonov7e843492013-03-28 15:42:43 +000057 FastPoisonShadowPartialRightRedzone(
Kostya Serebryanya3b0e5e2013-01-23 11:14:21 +000058 g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
59 g.size % SHADOW_GRANULARITY,
60 SHADOW_GRANULARITY,
61 kAsanGlobalRedzoneMagic);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000062 }
63}
64
Alexey Samsonov05e16a02013-03-26 13:06:12 +000065static void ReportGlobal(const Global &g, const char *prefix) {
66 Report("%s Global: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
67 prefix, (void*)g.beg, g.size, g.size_with_redzone, g.name,
68 g.module_name, g.has_dynamic_init);
69}
70
Evgeniy Stepanov589dcda2013-02-05 14:32:03 +000071bool DescribeAddressIfGlobal(uptr addr, uptr size) {
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +000072 if (!flags()->report_globals) return false;
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +000073 BlockingMutexLock lock(&mu_for_globals);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000074 bool res = false;
Kostya Serebryany3945c582012-08-21 14:10:25 +000075 for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
Kostya Serebryanyb89567c2011-12-02 21:02:20 +000076 const Global &g = *l->g;
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +000077 if (flags()->report_globals >= 2)
Alexey Samsonov05e16a02013-03-26 13:06:12 +000078 ReportGlobal(g, "Search");
Evgeniy Stepanov589dcda2013-02-05 14:32:03 +000079 res |= DescribeAddressRelativeToGlobal(addr, size, g);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000080 }
81 return res;
82}
83
84// Register a global variable.
85// This function may be called more than once for every global
86// so we store the globals in a map.
87static void RegisterGlobal(const Global *g) {
88 CHECK(asan_inited);
Kostya Serebryany3945c582012-08-21 14:10:25 +000089 if (flags()->report_globals >= 2)
Alexey Samsonov05e16a02013-03-26 13:06:12 +000090 ReportGlobal(*g, "Added");
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +000091 CHECK(flags()->report_globals);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000092 CHECK(AddrIsInMem(g->beg));
Kostya Serebryanyb89567c2011-12-02 21:02:20 +000093 CHECK(AddrIsAlignedByGranularity(g->beg));
Kostya Serebryanyc4910612011-12-15 21:55:34 +000094 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
Alexey Samsonov7e843492013-03-28 15:42:43 +000095 if (flags()->poison_heap)
96 PoisonRedZones(*g);
Kostya Serebryanyb89567c2011-12-02 21:02:20 +000097 ListOfGlobals *l =
98 (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
99 l->g = g;
Kostya Serebryany3945c582012-08-21 14:10:25 +0000100 l->next = list_of_all_globals;
101 list_of_all_globals = l;
102 if (g->has_dynamic_init) {
Alexey Samsonov7e843492013-03-28 15:42:43 +0000103 if (dynamic_init_globals == 0) {
104 void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals));
105 dynamic_init_globals = new(mem)
106 VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
107 }
Alexey Samsonovdfeef672013-04-19 08:35:16 +0000108 DynInitGlobal dyn_global = { *g, false };
109 dynamic_init_globals->push_back(dyn_global);
Kostya Serebryany3945c582012-08-21 14:10:25 +0000110 }
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000111}
112
Kostya Serebryanyc4910612011-12-15 21:55:34 +0000113static void UnregisterGlobal(const Global *g) {
114 CHECK(asan_inited);
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000115 CHECK(flags()->report_globals);
Kostya Serebryanyc4910612011-12-15 21:55:34 +0000116 CHECK(AddrIsInMem(g->beg));
117 CHECK(AddrIsAlignedByGranularity(g->beg));
118 CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
Alexey Samsonov7e843492013-03-28 15:42:43 +0000119 if (flags()->poison_heap)
120 PoisonShadowForGlobal(g, 0);
Kostya Serebryanyc4910612011-12-15 21:55:34 +0000121 // We unpoison the shadow memory for the global but we do not remove it from
122 // the list because that would require O(n^2) time with the current list
123 // implementation. It might not be worth doing anyway.
124}
125
Alexey Samsonov46efcb02013-05-24 11:46:56 +0000126void StopInitOrderChecking() {
127 BlockingMutexLock lock(&mu_for_globals);
128 if (!flags()->check_initialization_order || !dynamic_init_globals)
129 return;
130 flags()->check_initialization_order = false;
131 for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
132 DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
133 const Global *g = &dyn_g.g;
134 // Unpoison the whole global.
135 PoisonShadowForGlobal(g, 0);
136 // Poison redzones back.
137 PoisonRedZones(*g);
138 }
139}
140
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000141} // namespace __asan
142
143// ---------------------- Interface ---------------- {{{1
144using namespace __asan; // NOLINT
145
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000146// Register an array of globals.
Kostya Serebryany9aead372012-05-31 14:11:07 +0000147void __asan_register_globals(__asan_global *globals, uptr n) {
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000148 if (!flags()->report_globals) return;
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000149 BlockingMutexLock lock(&mu_for_globals);
Kostya Serebryany9aead372012-05-31 14:11:07 +0000150 for (uptr i = 0; i < n; i++) {
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000151 RegisterGlobal(&globals[i]);
152 }
153}
Kostya Serebryanyc4910612011-12-15 21:55:34 +0000154
155// Unregister an array of globals.
Kostya Serebryany3945c582012-08-21 14:10:25 +0000156// We must do this when a shared objects gets dlclosed.
Kostya Serebryany9aead372012-05-31 14:11:07 +0000157void __asan_unregister_globals(__asan_global *globals, uptr n) {
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000158 if (!flags()->report_globals) return;
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000159 BlockingMutexLock lock(&mu_for_globals);
Kostya Serebryany9aead372012-05-31 14:11:07 +0000160 for (uptr i = 0; i < n; i++) {
Kostya Serebryanyc4910612011-12-15 21:55:34 +0000161 UnregisterGlobal(&globals[i]);
162 }
163}
Kostya Serebryany3945c582012-08-21 14:10:25 +0000164
165// This method runs immediately prior to dynamic initialization in each TU,
166// when all dynamically initialized globals are unpoisoned. This method
167// poisons all global variables not defined in this TU, so that a dynamic
168// initializer can only touch global variables in the same TU.
Alexey Samsonov05e16a02013-03-26 13:06:12 +0000169void __asan_before_dynamic_init(const char *module_name) {
Alexey Samsonov7e843492013-03-28 15:42:43 +0000170 if (!flags()->check_initialization_order ||
171 !flags()->poison_heap)
172 return;
Alexey Samsonovdfeef672013-04-19 08:35:16 +0000173 bool strict_init_order = flags()->strict_init_order;
Alexey Samsonov7e843492013-03-28 15:42:43 +0000174 CHECK(dynamic_init_globals);
Alexey Samsonov05e16a02013-03-26 13:06:12 +0000175 CHECK(module_name);
Alexey Samsonov7e843492013-03-28 15:42:43 +0000176 CHECK(asan_inited);
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000177 BlockingMutexLock lock(&mu_for_globals);
Alexey Samsonov7e843492013-03-28 15:42:43 +0000178 if (flags()->report_globals >= 3)
179 Printf("DynInitPoison module: %s\n", module_name);
180 for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
Alexey Samsonovdfeef672013-04-19 08:35:16 +0000181 DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
182 const Global *g = &dyn_g.g;
183 if (dyn_g.initialized)
184 continue;
Alexey Samsonov7e843492013-03-28 15:42:43 +0000185 if (g->module_name != module_name)
186 PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
Alexey Samsonovdfeef672013-04-19 08:35:16 +0000187 else if (!strict_init_order)
188 dyn_g.initialized = true;
Kostya Serebryany3945c582012-08-21 14:10:25 +0000189 }
Kostya Serebryany3945c582012-08-21 14:10:25 +0000190}
191
192// This method runs immediately after dynamic initialization in each TU, when
193// all dynamically initialized globals except for those defined in the current
194// TU are poisoned. It simply unpoisons all dynamically initialized globals.
195void __asan_after_dynamic_init() {
Alexey Samsonov7e843492013-03-28 15:42:43 +0000196 if (!flags()->check_initialization_order ||
197 !flags()->poison_heap)
198 return;
199 CHECK(asan_inited);
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000200 BlockingMutexLock lock(&mu_for_globals);
Alexey Samsonov7e843492013-03-28 15:42:43 +0000201 // FIXME: Optionally report that we're unpoisoning globals from a module.
202 for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
Alexey Samsonovdfeef672013-04-19 08:35:16 +0000203 DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
204 const Global *g = &dyn_g.g;
205 if (!dyn_g.initialized) {
206 // Unpoison the whole global.
207 PoisonShadowForGlobal(g, 0);
208 // Poison redzones back.
209 PoisonRedZones(*g);
210 }
Alexey Samsonov7e843492013-03-28 15:42:43 +0000211 }
Kostya Serebryany3945c582012-08-21 14:10:25 +0000212}