]>
Commit | Line | Data |
---|---|---|
f35db108 WM |
1 | //===-- asan_rtl.cc -------------------------------------------------------===// |
2 | // | |
3 | // This file is distributed under the University of Illinois Open Source | |
4 | // License. See LICENSE.TXT for details. | |
5 | // | |
6 | //===----------------------------------------------------------------------===// | |
7 | // | |
8 | // This file is a part of AddressSanitizer, an address sanity checker. | |
9 | // | |
10 | // Main file of the ASan run-time library. | |
11 | //===----------------------------------------------------------------------===// | |
12 | #include "asan_allocator.h" | |
13 | #include "asan_interceptors.h" | |
ef1b3fda | 14 | #include "asan_interface_internal.h" |
f35db108 | 15 | #include "asan_internal.h" |
f35db108 | 16 | #include "asan_mapping.h" |
ef1b3fda | 17 | #include "asan_poisoning.h" |
f35db108 WM |
18 | #include "asan_report.h" |
19 | #include "asan_stack.h" | |
20 | #include "asan_stats.h" | |
21 | #include "asan_thread.h" | |
f35db108 WM |
22 | #include "sanitizer_common/sanitizer_atomic.h" |
23 | #include "sanitizer_common/sanitizer_flags.h" | |
24 | #include "sanitizer_common/sanitizer_libc.h" | |
25 | #include "sanitizer_common/sanitizer_symbolizer.h" | |
ef1b3fda KS |
26 | #include "lsan/lsan_common.h" |
27 | ||
28 | int __asan_option_detect_stack_use_after_return; // Global interface symbol. | |
f35db108 WM |
29 | |
30 | namespace __asan { | |
31 | ||
7df59255 KS |
32 | uptr AsanMappingProfile[kAsanMappingProfileSize]; |
33 | ||
f35db108 WM |
34 | static void AsanDie() { |
35 | static atomic_uint32_t num_calls; | |
36 | if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) { | |
37 | // Don't die twice - run a busy loop. | |
38 | while (1) { } | |
39 | } | |
40 | if (flags()->sleep_before_dying) { | |
41 | Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); | |
42 | SleepForSeconds(flags()->sleep_before_dying); | |
43 | } | |
7df59255 KS |
44 | if (flags()->unmap_shadow_on_exit) { |
45 | if (kMidMemBeg) { | |
46 | UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); | |
47 | UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd); | |
48 | } else { | |
49 | UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); | |
50 | } | |
51 | } | |
df77f0e4 KS |
52 | if (flags()->coverage) |
53 | __sanitizer_cov_dump(); | |
f35db108 WM |
54 | if (death_callback) |
55 | death_callback(); | |
56 | if (flags()->abort_on_error) | |
57 | Abort(); | |
7df59255 | 58 | internal__exit(flags()->exitcode); |
f35db108 WM |
59 | } |
60 | ||
61 | static void AsanCheckFailed(const char *file, int line, const char *cond, | |
62 | u64 v1, u64 v2) { | |
63 | Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", | |
64 | file, line, cond, (uptr)v1, (uptr)v2); | |
65 | // FIXME: check for infinite recursion without a thread-local counter here. | |
66 | PRINT_CURRENT_STACK(); | |
e9772e16 | 67 | Die(); |
f35db108 WM |
68 | } |
69 | ||
70 | // -------------------------- Flags ------------------------- {{{1 | |
ef1b3fda | 71 | static const int kDefaultMallocContextSize = 30; |
f35db108 | 72 | |
ef1b3fda | 73 | Flags asan_flags_dont_use_directly; // use via flags(). |
f35db108 | 74 | |
e9772e16 KS |
75 | static const char *MaybeCallAsanDefaultOptions() { |
76 | return (&__asan_default_options) ? __asan_default_options() : ""; | |
77 | } | |
78 | ||
7df59255 KS |
79 | static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() { |
80 | #ifdef ASAN_DEFAULT_OPTIONS | |
81 | // Stringize the macro value. | |
82 | # define ASAN_STRINGIZE(x) #x | |
83 | # define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options) | |
84 | return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS); | |
85 | #else | |
86 | return ""; | |
87 | #endif | |
88 | } | |
89 | ||
f35db108 | 90 | static void ParseFlagsFromString(Flags *f, const char *str) { |
df77f0e4 KS |
91 | CommonFlags *cf = common_flags(); |
92 | ParseCommonFlagsFromString(cf, str); | |
93 | CHECK((uptr)cf->malloc_context_size <= kStackTraceMax); | |
ef1b3fda | 94 | |
f35db108 | 95 | ParseFlag(str, &f->quarantine_size, "quarantine_size"); |
f35db108 | 96 | ParseFlag(str, &f->redzone, "redzone"); |
ef1b3fda | 97 | CHECK_GE(f->redzone, 16); |
f35db108 WM |
98 | CHECK(IsPowerOfTwo(f->redzone)); |
99 | ||
100 | ParseFlag(str, &f->debug, "debug"); | |
101 | ParseFlag(str, &f->report_globals, "report_globals"); | |
ef1b3fda | 102 | ParseFlag(str, &f->check_initialization_order, "check_initialization_order"); |
f35db108 WM |
103 | |
104 | ParseFlag(str, &f->replace_str, "replace_str"); | |
105 | ParseFlag(str, &f->replace_intrin, "replace_intrin"); | |
f35db108 | 106 | ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free"); |
ef1b3fda KS |
107 | ParseFlag(str, &f->detect_stack_use_after_return, |
108 | "detect_stack_use_after_return"); | |
109 | ParseFlag(str, &f->uar_stack_size_log, "uar_stack_size_log"); | |
f35db108 | 110 | ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size"); |
ef1b3fda | 111 | ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte"); |
f35db108 WM |
112 | ParseFlag(str, &f->exitcode, "exitcode"); |
113 | ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning"); | |
114 | ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying"); | |
115 | ParseFlag(str, &f->handle_segv, "handle_segv"); | |
ef1b3fda | 116 | ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler"); |
f35db108 WM |
117 | ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack"); |
118 | ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size"); | |
119 | ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit"); | |
120 | ParseFlag(str, &f->abort_on_error, "abort_on_error"); | |
b4ab7d34 KS |
121 | ParseFlag(str, &f->print_stats, "print_stats"); |
122 | ParseFlag(str, &f->print_legend, "print_legend"); | |
f35db108 | 123 | ParseFlag(str, &f->atexit, "atexit"); |
df77f0e4 | 124 | ParseFlag(str, &f->coverage, "coverage"); |
f35db108 | 125 | ParseFlag(str, &f->disable_core, "disable_core"); |
f35db108 WM |
126 | ParseFlag(str, &f->allow_reexec, "allow_reexec"); |
127 | ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history"); | |
e9772e16 | 128 | ParseFlag(str, &f->poison_heap, "poison_heap"); |
df77f0e4 | 129 | ParseFlag(str, &f->poison_partial, "poison_partial"); |
e9772e16 | 130 | ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch"); |
ef1b3fda KS |
131 | ParseFlag(str, &f->strict_memcmp, "strict_memcmp"); |
132 | ParseFlag(str, &f->strict_init_order, "strict_init_order"); | |
f35db108 WM |
133 | } |
134 | ||
f35db108 | 135 | void InitializeFlags(Flags *f, const char *env) { |
ef1b3fda | 136 | CommonFlags *cf = common_flags(); |
df77f0e4 | 137 | SetCommonFlagsDefaults(cf); |
ef1b3fda | 138 | cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); |
ef1b3fda | 139 | cf->malloc_context_size = kDefaultMallocContextSize; |
f35db108 | 140 | |
ef1b3fda | 141 | internal_memset(f, 0, sizeof(*f)); |
f35db108 | 142 | f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28; |
ef1b3fda | 143 | f->redzone = 16; |
f35db108 WM |
144 | f->debug = false; |
145 | f->report_globals = 1; | |
ef1b3fda | 146 | f->check_initialization_order = false; |
f35db108 WM |
147 | f->replace_str = true; |
148 | f->replace_intrin = true; | |
f35db108 | 149 | f->mac_ignore_invalid_free = false; |
ef1b3fda KS |
150 | f->detect_stack_use_after_return = false; // Also needs the compiler flag. |
151 | f->uar_stack_size_log = 0; | |
152 | f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K. | |
153 | f->malloc_fill_byte = 0xbe; | |
f35db108 WM |
154 | f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE; |
155 | f->allow_user_poisoning = true; | |
156 | f->sleep_before_dying = 0; | |
157 | f->handle_segv = ASAN_NEEDS_SEGV; | |
ef1b3fda | 158 | f->allow_user_segv_handler = false; |
f35db108 WM |
159 | f->use_sigaltstack = false; |
160 | f->check_malloc_usable_size = true; | |
161 | f->unmap_shadow_on_exit = false; | |
162 | f->abort_on_error = false; | |
b4ab7d34 KS |
163 | f->print_stats = false; |
164 | f->print_legend = true; | |
f35db108 | 165 | f->atexit = false; |
df77f0e4 | 166 | f->coverage = false; |
e297eb60 | 167 | f->disable_core = (SANITIZER_WORDSIZE == 64); |
f35db108 WM |
168 | f->allow_reexec = true; |
169 | f->print_full_thread_history = true; | |
e9772e16 | 170 | f->poison_heap = true; |
df77f0e4 | 171 | f->poison_partial = true; |
ef1b3fda KS |
172 | // Turn off alloc/dealloc mismatch checker on Mac and Windows for now. |
173 | // TODO(glider,timurrrr): Fix known issues and enable this back. | |
174 | f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0); | |
ef1b3fda KS |
175 | f->strict_memcmp = true; |
176 | f->strict_init_order = false; | |
f35db108 | 177 | |
7df59255 KS |
178 | // Override from compile definition. |
179 | ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton()); | |
180 | ||
f35db108 | 181 | // Override from user-specified string. |
e9772e16 | 182 | ParseFlagsFromString(f, MaybeCallAsanDefaultOptions()); |
df77f0e4 | 183 | if (cf->verbosity) { |
f35db108 | 184 | Report("Using the defaults from __asan_default_options: %s\n", |
e9772e16 | 185 | MaybeCallAsanDefaultOptions()); |
f35db108 WM |
186 | } |
187 | ||
188 | // Override from command line. | |
189 | ParseFlagsFromString(f, env); | |
ef1b3fda KS |
190 | |
191 | #if !CAN_SANITIZE_LEAKS | |
192 | if (cf->detect_leaks) { | |
193 | Report("%s: detect_leaks is not supported on this platform.\n", | |
194 | SanitizerToolName); | |
195 | cf->detect_leaks = false; | |
196 | } | |
197 | #endif | |
198 | ||
df77f0e4 KS |
199 | // Make "strict_init_order" imply "check_initialization_order". |
200 | // TODO(samsonov): Use a single runtime flag for an init-order checker. | |
201 | if (f->strict_init_order) { | |
202 | f->check_initialization_order = true; | |
ef1b3fda | 203 | } |
f35db108 WM |
204 | } |
205 | ||
206 | // -------------------------- Globals --------------------- {{{1 | |
207 | int asan_inited; | |
208 | bool asan_init_is_running; | |
209 | void (*death_callback)(void); | |
7df59255 KS |
210 | |
211 | #if !ASAN_FIXED_MAPPING | |
212 | uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; | |
213 | #endif | |
f35db108 WM |
214 | |
215 | // -------------------------- Misc ---------------- {{{1 | |
216 | void ShowStatsAndAbort() { | |
217 | __asan_print_accumulated_stats(); | |
218 | Die(); | |
219 | } | |
220 | ||
221 | // ---------------------- mmap -------------------- {{{1 | |
222 | // Reserve memory range [beg, end]. | |
223 | static void ReserveShadowMemoryRange(uptr beg, uptr end) { | |
ef1b3fda KS |
224 | CHECK_EQ((beg % GetPageSizeCached()), 0); |
225 | CHECK_EQ(((end + 1) % GetPageSizeCached()), 0); | |
f35db108 WM |
226 | uptr size = end - beg + 1; |
227 | void *res = MmapFixedNoReserve(beg, size); | |
228 | if (res != (void*)beg) { | |
229 | Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " | |
230 | "Perhaps you're using ulimit -v\n", size); | |
231 | Abort(); | |
232 | } | |
233 | } | |
234 | ||
235 | // --------------- LowLevelAllocateCallbac ---------- {{{1 | |
236 | static void OnLowLevelAllocate(uptr ptr, uptr size) { | |
237 | PoisonShadow(ptr, size, kAsanInternalHeapMagic); | |
238 | } | |
239 | ||
240 | // -------------------------- Run-time entry ------------------- {{{1 | |
241 | // exported functions | |
242 | #define ASAN_REPORT_ERROR(type, is_write, size) \ | |
243 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ | |
244 | void __asan_report_ ## type ## size(uptr addr); \ | |
245 | void __asan_report_ ## type ## size(uptr addr) { \ | |
246 | GET_CALLER_PC_BP_SP; \ | |
247 | __asan_report_error(pc, bp, sp, addr, is_write, size); \ | |
248 | } | |
249 | ||
250 | ASAN_REPORT_ERROR(load, false, 1) | |
251 | ASAN_REPORT_ERROR(load, false, 2) | |
252 | ASAN_REPORT_ERROR(load, false, 4) | |
253 | ASAN_REPORT_ERROR(load, false, 8) | |
254 | ASAN_REPORT_ERROR(load, false, 16) | |
255 | ASAN_REPORT_ERROR(store, true, 1) | |
256 | ASAN_REPORT_ERROR(store, true, 2) | |
257 | ASAN_REPORT_ERROR(store, true, 4) | |
258 | ASAN_REPORT_ERROR(store, true, 8) | |
259 | ASAN_REPORT_ERROR(store, true, 16) | |
260 | ||
7df59255 KS |
261 | #define ASAN_REPORT_ERROR_N(type, is_write) \ |
262 | extern "C" NOINLINE INTERFACE_ATTRIBUTE \ | |
263 | void __asan_report_ ## type ## _n(uptr addr, uptr size); \ | |
264 | void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ | |
265 | GET_CALLER_PC_BP_SP; \ | |
266 | __asan_report_error(pc, bp, sp, addr, is_write, size); \ | |
267 | } | |
268 | ||
269 | ASAN_REPORT_ERROR_N(load, false) | |
270 | ASAN_REPORT_ERROR_N(store, true) | |
271 | ||
f35db108 WM |
272 | // Force the linker to keep the symbols for various ASan interface functions. |
273 | // We want to keep those in the executable in order to let the instrumented | |
274 | // dynamic libraries access the symbol even if it is not used by the executable | |
275 | // itself. This should help if the build system is removing dead code at link | |
276 | // time. | |
277 | static NOINLINE void force_interface_symbols() { | |
278 | volatile int fake_condition = 0; // prevent dead condition elimination. | |
279 | // __asan_report_* functions are noreturn, so we need a switch to prevent | |
280 | // the compiler from removing any of them. | |
281 | switch (fake_condition) { | |
282 | case 1: __asan_report_load1(0); break; | |
283 | case 2: __asan_report_load2(0); break; | |
284 | case 3: __asan_report_load4(0); break; | |
285 | case 4: __asan_report_load8(0); break; | |
286 | case 5: __asan_report_load16(0); break; | |
287 | case 6: __asan_report_store1(0); break; | |
288 | case 7: __asan_report_store2(0); break; | |
289 | case 8: __asan_report_store4(0); break; | |
290 | case 9: __asan_report_store8(0); break; | |
291 | case 10: __asan_report_store16(0); break; | |
f35db108 WM |
292 | case 12: __asan_register_globals(0, 0); break; |
293 | case 13: __asan_unregister_globals(0, 0); break; | |
294 | case 14: __asan_set_death_callback(0); break; | |
295 | case 15: __asan_set_error_report_callback(0); break; | |
296 | case 16: __asan_handle_no_return(); break; | |
297 | case 17: __asan_address_is_poisoned(0); break; | |
298 | case 18: __asan_get_allocated_size(0); break; | |
299 | case 19: __asan_get_current_allocated_bytes(); break; | |
300 | case 20: __asan_get_estimated_allocated_size(0); break; | |
301 | case 21: __asan_get_free_bytes(); break; | |
302 | case 22: __asan_get_heap_size(); break; | |
303 | case 23: __asan_get_ownership(0); break; | |
304 | case 24: __asan_get_unmapped_bytes(); break; | |
305 | case 25: __asan_poison_memory_region(0, 0); break; | |
306 | case 26: __asan_unpoison_memory_region(0, 0); break; | |
307 | case 27: __asan_set_error_exit_code(0); break; | |
ef1b3fda | 308 | case 30: __asan_before_dynamic_init(0); break; |
e9772e16 KS |
309 | case 31: __asan_after_dynamic_init(); break; |
310 | case 32: __asan_poison_stack_memory(0, 0); break; | |
311 | case 33: __asan_unpoison_stack_memory(0, 0); break; | |
312 | case 34: __asan_region_is_poisoned(0, 0); break; | |
313 | case 35: __asan_describe_address(0); break; | |
f35db108 WM |
314 | } |
315 | } | |
316 | ||
317 | static void asan_atexit() { | |
318 | Printf("AddressSanitizer exit stats:\n"); | |
319 | __asan_print_accumulated_stats(); | |
7df59255 KS |
320 | // Print AsanMappingProfile. |
321 | for (uptr i = 0; i < kAsanMappingProfileSize; i++) { | |
322 | if (AsanMappingProfile[i] == 0) continue; | |
323 | Printf("asan_mapping.h:%zd -- %zd\n", i, AsanMappingProfile[i]); | |
324 | } | |
f35db108 WM |
325 | } |
326 | ||
b4ab7d34 | 327 | static void InitializeHighMemEnd() { |
7df59255 | 328 | #if !ASAN_FIXED_MAPPING |
ef1b3fda KS |
329 | kHighMemEnd = GetMaxVirtualAddress(); |
330 | // Increase kHighMemEnd to make sure it's properly | |
331 | // aligned together with kHighMemBeg: | |
332 | kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1; | |
7df59255 | 333 | #endif // !ASAN_FIXED_MAPPING |
ef1b3fda | 334 | CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0); |
7df59255 KS |
335 | } |
336 | ||
337 | static void ProtectGap(uptr a, uptr size) { | |
338 | CHECK_EQ(a, (uptr)Mprotect(a, size)); | |
339 | } | |
340 | ||
341 | static void PrintAddressSpaceLayout() { | |
342 | Printf("|| `[%p, %p]` || HighMem ||\n", | |
343 | (void*)kHighMemBeg, (void*)kHighMemEnd); | |
344 | Printf("|| `[%p, %p]` || HighShadow ||\n", | |
345 | (void*)kHighShadowBeg, (void*)kHighShadowEnd); | |
346 | if (kMidMemBeg) { | |
347 | Printf("|| `[%p, %p]` || ShadowGap3 ||\n", | |
348 | (void*)kShadowGap3Beg, (void*)kShadowGap3End); | |
349 | Printf("|| `[%p, %p]` || MidMem ||\n", | |
350 | (void*)kMidMemBeg, (void*)kMidMemEnd); | |
351 | Printf("|| `[%p, %p]` || ShadowGap2 ||\n", | |
352 | (void*)kShadowGap2Beg, (void*)kShadowGap2End); | |
353 | Printf("|| `[%p, %p]` || MidShadow ||\n", | |
354 | (void*)kMidShadowBeg, (void*)kMidShadowEnd); | |
355 | } | |
356 | Printf("|| `[%p, %p]` || ShadowGap ||\n", | |
357 | (void*)kShadowGapBeg, (void*)kShadowGapEnd); | |
358 | if (kLowShadowBeg) { | |
359 | Printf("|| `[%p, %p]` || LowShadow ||\n", | |
360 | (void*)kLowShadowBeg, (void*)kLowShadowEnd); | |
361 | Printf("|| `[%p, %p]` || LowMem ||\n", | |
362 | (void*)kLowMemBeg, (void*)kLowMemEnd); | |
363 | } | |
364 | Printf("MemToShadow(shadow): %p %p %p %p", | |
365 | (void*)MEM_TO_SHADOW(kLowShadowBeg), | |
366 | (void*)MEM_TO_SHADOW(kLowShadowEnd), | |
367 | (void*)MEM_TO_SHADOW(kHighShadowBeg), | |
368 | (void*)MEM_TO_SHADOW(kHighShadowEnd)); | |
369 | if (kMidMemBeg) { | |
370 | Printf(" %p %p", | |
371 | (void*)MEM_TO_SHADOW(kMidShadowBeg), | |
372 | (void*)MEM_TO_SHADOW(kMidShadowEnd)); | |
373 | } | |
374 | Printf("\n"); | |
375 | Printf("red_zone=%zu\n", (uptr)flags()->redzone); | |
ef1b3fda KS |
376 | Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20); |
377 | Printf("malloc_context_size=%zu\n", | |
378 | (uptr)common_flags()->malloc_context_size); | |
7df59255 KS |
379 | |
380 | Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE); | |
381 | Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY); | |
382 | Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET); | |
383 | CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7); | |
384 | if (kMidMemBeg) | |
385 | CHECK(kMidShadowBeg > kLowShadowEnd && | |
386 | kMidMemBeg > kMidShadowEnd && | |
387 | kHighShadowBeg > kMidMemEnd); | |
b4ab7d34 KS |
388 | } |
389 | ||
f35db108 WM |
390 | } // namespace __asan |
391 | ||
392 | // ---------------------- Interface ---------------- {{{1 | |
393 | using namespace __asan; // NOLINT | |
394 | ||
e9772e16 KS |
395 | #if !SANITIZER_SUPPORTS_WEAK_HOOKS |
396 | extern "C" { | |
ef1b3fda | 397 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
e9772e16 KS |
398 | const char* __asan_default_options() { return ""; } |
399 | } // extern "C" | |
400 | #endif | |
401 | ||
f35db108 WM |
402 | int NOINLINE __asan_set_error_exit_code(int exit_code) { |
403 | int old = flags()->exitcode; | |
404 | flags()->exitcode = exit_code; | |
405 | return old; | |
406 | } | |
407 | ||
408 | void NOINLINE __asan_handle_no_return() { | |
409 | int local_stack; | |
ef1b3fda | 410 | AsanThread *curr_thread = GetCurrentThread(); |
f35db108 | 411 | CHECK(curr_thread); |
4ba5ca46 | 412 | uptr PageSize = GetPageSizeCached(); |
f35db108 | 413 | uptr top = curr_thread->stack_top(); |
4ba5ca46 | 414 | uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1); |
ef1b3fda KS |
415 | static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M |
416 | if (top - bottom > kMaxExpectedCleanupSize) { | |
417 | static bool reported_warning = false; | |
418 | if (reported_warning) | |
419 | return; | |
420 | reported_warning = true; | |
421 | Report("WARNING: ASan is ignoring requested __asan_handle_no_return: " | |
422 | "stack top: %p; bottom %p; size: %p (%zd)\n" | |
423 | "False positive error reports may follow\n" | |
424 | "For details see " | |
425 | "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n", | |
426 | top, bottom, top - bottom, top - bottom); | |
427 | return; | |
428 | } | |
f35db108 | 429 | PoisonShadow(bottom, top - bottom, 0); |
ef1b3fda KS |
430 | if (curr_thread->has_fake_stack()) |
431 | curr_thread->fake_stack()->HandleNoReturn(); | |
f35db108 WM |
432 | } |
433 | ||
434 | void NOINLINE __asan_set_death_callback(void (*callback)(void)) { | |
435 | death_callback = callback; | |
436 | } | |
437 | ||
438 | void __asan_init() { | |
439 | if (asan_inited) return; | |
b4ab7d34 | 440 | SanitizerToolName = "AddressSanitizer"; |
f35db108 WM |
441 | CHECK(!asan_init_is_running && "ASan init calls itself!"); |
442 | asan_init_is_running = true; | |
b4ab7d34 | 443 | InitializeHighMemEnd(); |
f35db108 WM |
444 | |
445 | // Make sure we are not statically linked. | |
446 | AsanDoesNotSupportStaticLinkage(); | |
447 | ||
448 | // Install tool-specific callbacks in sanitizer_common. | |
449 | SetDieCallback(AsanDie); | |
450 | SetCheckFailedCallback(AsanCheckFailed); | |
451 | SetPrintfAndReportCallback(AppendToErrorMessageBuffer); | |
452 | ||
453 | // Initialize flags. This must be done early, because most of the | |
454 | // initialization steps look at flags(). | |
455 | const char *options = GetEnv("ASAN_OPTIONS"); | |
456 | InitializeFlags(flags(), options); | |
ef1b3fda KS |
457 | __sanitizer_set_report_path(common_flags()->log_path); |
458 | __asan_option_detect_stack_use_after_return = | |
459 | flags()->detect_stack_use_after_return; | |
f35db108 | 460 | |
df77f0e4 | 461 | if (common_flags()->verbosity && options) { |
f35db108 WM |
462 | Report("Parsed ASAN_OPTIONS: %s\n", options); |
463 | } | |
464 | ||
465 | // Re-exec ourselves if we need to set additional env or command line args. | |
466 | MaybeReexec(); | |
467 | ||
468 | // Setup internal allocator callback. | |
469 | SetLowLevelAllocateCallback(OnLowLevelAllocate); | |
470 | ||
f35db108 WM |
471 | InitializeAsanInterceptors(); |
472 | ||
473 | ReplaceSystemMalloc(); | |
474 | ReplaceOperatorsNewAndDelete(); | |
475 | ||
7df59255 | 476 | uptr shadow_start = kLowShadowBeg; |
ef1b3fda KS |
477 | if (kLowShadowBeg) |
478 | shadow_start -= GetMmapGranularity(); | |
7df59255 | 479 | bool full_shadow_is_available = |
ef1b3fda | 480 | MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); |
7df59255 | 481 | |
ef1b3fda | 482 | #if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING |
7df59255 KS |
483 | if (!full_shadow_is_available) { |
484 | kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; | |
4c376126 | 485 | kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; |
f35db108 | 486 | } |
7df59255 KS |
487 | #endif |
488 | ||
df77f0e4 | 489 | if (common_flags()->verbosity) |
7df59255 | 490 | PrintAddressSpaceLayout(); |
f35db108 WM |
491 | |
492 | if (flags()->disable_core) { | |
493 | DisableCoreDumper(); | |
494 | } | |
495 | ||
7df59255 KS |
496 | if (full_shadow_is_available) { |
497 | // mmap the low shadow plus at least one page at the left. | |
498 | if (kLowShadowBeg) | |
499 | ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); | |
500 | // mmap the high shadow. | |
501 | ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); | |
502 | // protect the gap. | |
503 | ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); | |
504 | } else if (kMidMemBeg && | |
505 | MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && | |
ef1b3fda | 506 | MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { |
7df59255 KS |
507 | CHECK(kLowShadowBeg != kLowShadowEnd); |
508 | // mmap the low shadow plus at least one page at the left. | |
509 | ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); | |
510 | // mmap the mid shadow. | |
511 | ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd); | |
f35db108 WM |
512 | // mmap the high shadow. |
513 | ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); | |
7df59255 KS |
514 | // protect the gaps. |
515 | ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); | |
516 | ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); | |
517 | ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); | |
f35db108 WM |
518 | } else { |
519 | Report("Shadow memory range interleaves with an existing memory mapping. " | |
520 | "ASan cannot proceed correctly. ABORTING.\n"); | |
521 | DumpProcessMap(); | |
522 | Die(); | |
523 | } | |
524 | ||
df77f0e4 | 525 | AsanTSDInit(PlatformTSDDtor); |
f35db108 | 526 | InstallSignalHandlers(); |
ef1b3fda | 527 | |
ef1b3fda KS |
528 | // Allocator should be initialized before starting external symbolizer, as |
529 | // fork() on Mac locks the allocator. | |
530 | InitializeAllocator(); | |
531 | ||
f35db108 | 532 | // Start symbolizer process if necessary. |
df77f0e4 KS |
533 | if (common_flags()->symbolize) { |
534 | Symbolizer::Init(common_flags()->external_symbolizer_path); | |
535 | } else { | |
536 | Symbolizer::Disable(); | |
f35db108 WM |
537 | } |
538 | ||
539 | // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited | |
540 | // should be set to 1 prior to initializing the threads. | |
541 | asan_inited = 1; | |
542 | asan_init_is_running = false; | |
543 | ||
df77f0e4 KS |
544 | if (flags()->atexit) |
545 | Atexit(asan_atexit); | |
546 | ||
547 | if (flags()->coverage) | |
548 | Atexit(__sanitizer_cov_dump); | |
549 | ||
550 | // interceptors | |
ef1b3fda KS |
551 | InitTlsSize(); |
552 | ||
553 | // Create main thread. | |
554 | AsanThread *main_thread = AsanThread::Create(0, 0); | |
555 | CreateThreadContextArgs create_main_args = { main_thread, 0 }; | |
556 | u32 main_tid = asanThreadRegistry().CreateThread( | |
557 | 0, true, 0, &create_main_args); | |
558 | CHECK_EQ(0, main_tid); | |
559 | SetCurrentThread(main_thread); | |
560 | main_thread->ThreadStart(internal_getpid()); | |
f35db108 WM |
561 | force_interface_symbols(); // no-op. |
562 | ||
ef1b3fda KS |
563 | #if CAN_SANITIZE_LEAKS |
564 | __lsan::InitCommonLsan(); | |
565 | if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { | |
566 | Atexit(__lsan::DoLeakCheck); | |
567 | } | |
568 | #endif // CAN_SANITIZE_LEAKS | |
b4ab7d34 | 569 | |
df77f0e4 | 570 | if (common_flags()->verbosity) { |
f35db108 WM |
571 | Report("AddressSanitizer Init done\n"); |
572 | } | |
573 | } |