1 | //===-- asan_flags.cpp ------------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of AddressSanitizer, an address sanity checker. |
10 | // |
11 | // ASan flag parsing logic. |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "asan_activation.h" |
15 | #include "asan_flags.h" |
16 | #include "asan_interface_internal.h" |
17 | #include "asan_stack.h" |
18 | #include "lsan/lsan_common.h" |
19 | #include "sanitizer_common/sanitizer_common.h" |
20 | #include "sanitizer_common/sanitizer_flags.h" |
21 | #include "sanitizer_common/sanitizer_flag_parser.h" |
22 | #include "ubsan/ubsan_flags.h" |
23 | #include "ubsan/ubsan_platform.h" |
24 | |
25 | namespace __asan { |
26 | |
27 | Flags asan_flags_dont_use_directly; // use via flags(). |
28 | |
29 | static const char *MaybeUseAsanDefaultOptionsCompileDefinition() { |
30 | #ifdef ASAN_DEFAULT_OPTIONS |
31 | return SANITIZER_STRINGIFY(ASAN_DEFAULT_OPTIONS); |
32 | #else |
33 | return "" ; |
34 | #endif |
35 | } |
36 | |
37 | void Flags::SetDefaults() { |
38 | #define ASAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; |
39 | #include "asan_flags.inc" |
40 | #undef ASAN_FLAG |
41 | } |
42 | |
43 | static void RegisterAsanFlags(FlagParser *parser, Flags *f) { |
44 | #define ASAN_FLAG(Type, Name, DefaultValue, Description) \ |
45 | RegisterFlag(parser, #Name, Description, &f->Name); |
46 | #include "asan_flags.inc" |
47 | #undef ASAN_FLAG |
48 | } |
49 | |
50 | void InitializeFlags() { |
51 | // Set the default values and prepare for parsing ASan and common flags. |
52 | SetCommonFlagsDefaults(); |
53 | { |
54 | CommonFlags cf; |
55 | cf.CopyFrom(other: *common_flags()); |
56 | cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS; |
57 | cf.external_symbolizer_path = GetEnv(name: "ASAN_SYMBOLIZER_PATH" ); |
58 | cf.malloc_context_size = kDefaultMallocContextSize; |
59 | cf.intercept_tls_get_addr = true; |
60 | cf.exitcode = 1; |
61 | OverrideCommonFlags(cf); |
62 | } |
63 | Flags *f = flags(); |
64 | f->SetDefaults(); |
65 | |
66 | FlagParser asan_parser; |
67 | RegisterAsanFlags(parser: &asan_parser, f); |
68 | RegisterCommonFlags(parser: &asan_parser); |
69 | |
70 | // Set the default values and prepare for parsing LSan and UBSan flags |
71 | // (which can also overwrite common flags). |
72 | #if CAN_SANITIZE_LEAKS |
73 | __lsan::Flags *lf = __lsan::flags(); |
74 | lf->SetDefaults(); |
75 | |
76 | FlagParser lsan_parser; |
77 | __lsan::RegisterLsanFlags(parser: &lsan_parser, f: lf); |
78 | RegisterCommonFlags(parser: &lsan_parser); |
79 | #endif |
80 | |
81 | #if CAN_SANITIZE_UB |
82 | __ubsan::Flags *uf = __ubsan::flags(); |
83 | uf->SetDefaults(); |
84 | |
85 | FlagParser ubsan_parser; |
86 | __ubsan::RegisterUbsanFlags(parser: &ubsan_parser, f: uf); |
87 | RegisterCommonFlags(parser: &ubsan_parser); |
88 | #endif |
89 | |
90 | if (SANITIZER_APPLE) { |
91 | // Support macOS MallocScribble and MallocPreScribble: |
92 | // <https://developer.apple.com/library/content/documentation/Performance/ |
93 | // Conceptual/ManagingMemory/Articles/MallocDebug.html> |
94 | if (GetEnv(name: "MallocScribble" )) { |
95 | f->max_free_fill_size = 0x1000; |
96 | } |
97 | if (GetEnv(name: "MallocPreScribble" )) { |
98 | f->malloc_fill_byte = 0xaa; |
99 | } |
100 | } |
101 | |
102 | // Override from ASan compile definition. |
103 | const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); |
104 | asan_parser.ParseString(s: asan_compile_def); |
105 | |
106 | // Override from user-specified string. |
107 | const char *asan_default_options = __asan_default_options(); |
108 | asan_parser.ParseString(s: asan_default_options); |
109 | #if CAN_SANITIZE_UB |
110 | const char *ubsan_default_options = __ubsan_default_options(); |
111 | ubsan_parser.ParseString(s: ubsan_default_options); |
112 | #endif |
113 | #if CAN_SANITIZE_LEAKS |
114 | const char *lsan_default_options = __lsan_default_options(); |
115 | lsan_parser.ParseString(s: lsan_default_options); |
116 | #endif |
117 | |
118 | // Override from command line. |
119 | asan_parser.ParseStringFromEnv(env_name: "ASAN_OPTIONS" ); |
120 | #if CAN_SANITIZE_LEAKS |
121 | lsan_parser.ParseStringFromEnv(env_name: "LSAN_OPTIONS" ); |
122 | #endif |
123 | #if CAN_SANITIZE_UB |
124 | ubsan_parser.ParseStringFromEnv(env_name: "UBSAN_OPTIONS" ); |
125 | #endif |
126 | |
127 | InitializeCommonFlags(); |
128 | |
129 | // TODO(eugenis): dump all flags at verbosity>=2? |
130 | if (Verbosity()) ReportUnrecognizedFlags(); |
131 | |
132 | if (common_flags()->help) { |
133 | // TODO(samsonov): print all of the flags (ASan, LSan, common). |
134 | asan_parser.PrintFlagDescriptions(); |
135 | } |
136 | |
137 | // Flag validation: |
138 | if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { |
139 | Report(format: "%s: detect_leaks is not supported on this platform.\n" , |
140 | SanitizerToolName); |
141 | Die(); |
142 | } |
143 | // Ensure that redzone is at least ASAN_SHADOW_GRANULARITY. |
144 | if (f->redzone < (int)ASAN_SHADOW_GRANULARITY) |
145 | f->redzone = ASAN_SHADOW_GRANULARITY; |
146 | // Make "strict_init_order" imply "check_initialization_order". |
147 | // TODO(samsonov): Use a single runtime flag for an init-order checker. |
148 | if (f->strict_init_order) { |
149 | f->check_initialization_order = true; |
150 | } |
151 | CHECK_LE((uptr)common_flags()->malloc_context_size, kStackTraceMax); |
152 | CHECK_LE(f->min_uar_stack_size_log, f->max_uar_stack_size_log); |
153 | CHECK_GE(f->redzone, 16); |
154 | CHECK_GE(f->max_redzone, f->redzone); |
155 | CHECK_LE(f->max_redzone, 2048); |
156 | CHECK(IsPowerOfTwo(f->redzone)); |
157 | CHECK(IsPowerOfTwo(f->max_redzone)); |
158 | |
159 | // quarantine_size is deprecated but we still honor it. |
160 | // quarantine_size can not be used together with quarantine_size_mb. |
161 | if (f->quarantine_size >= 0 && f->quarantine_size_mb >= 0) { |
162 | Report(format: "%s: please use either 'quarantine_size' (deprecated) or " |
163 | "quarantine_size_mb, but not both\n" , SanitizerToolName); |
164 | Die(); |
165 | } |
166 | if (f->quarantine_size >= 0) |
167 | f->quarantine_size_mb = f->quarantine_size >> 20; |
168 | if (f->quarantine_size_mb < 0) { |
169 | const int kDefaultQuarantineSizeMb = |
170 | (ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8; |
171 | f->quarantine_size_mb = kDefaultQuarantineSizeMb; |
172 | } |
173 | if (f->thread_local_quarantine_size_kb < 0) { |
174 | const u32 kDefaultThreadLocalQuarantineSizeKb = |
175 | // It is not advised to go lower than 64Kb, otherwise quarantine batches |
176 | // pushed from thread local quarantine to global one will create too |
177 | // much overhead. One quarantine batch size is 8Kb and it holds up to |
178 | // 1021 chunk, which amounts to 1/8 memory overhead per batch when |
179 | // thread local quarantine is set to 64Kb. |
180 | (ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10); |
181 | f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb; |
182 | } |
183 | if (f->thread_local_quarantine_size_kb == 0 && f->quarantine_size_mb > 0) { |
184 | Report(format: "%s: thread_local_quarantine_size_kb can be set to 0 only when " |
185 | "quarantine_size_mb is set to 0\n" , SanitizerToolName); |
186 | Die(); |
187 | } |
188 | if (!f->replace_str && common_flags()->intercept_strlen) { |
189 | Report(format: "WARNING: strlen interceptor is enabled even though replace_str=0. " |
190 | "Use intercept_strlen=0 to disable it." ); |
191 | } |
192 | if (!f->replace_str && common_flags()->intercept_strchr) { |
193 | Report(format: "WARNING: strchr* interceptors are enabled even though " |
194 | "replace_str=0. Use intercept_strchr=0 to disable them." ); |
195 | } |
196 | if (!f->replace_str && common_flags()->intercept_strndup) { |
197 | Report(format: "WARNING: strndup* interceptors are enabled even though " |
198 | "replace_str=0. Use intercept_strndup=0 to disable them." ); |
199 | } |
200 | } |
201 | |
202 | } // namespace __asan |
203 | |
204 | SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) { |
205 | return "" ; |
206 | } |
207 | |