| 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_flags.h" |
| 15 | |
| 16 | #include "asan_activation.h" |
| 17 | #include "asan_interface_internal.h" |
| 18 | #include "asan_stack.h" |
| 19 | #include "lsan/lsan_common.h" |
| 20 | #include "sanitizer_common/sanitizer_common.h" |
| 21 | #include "sanitizer_common/sanitizer_flag_parser.h" |
| 22 | #include "sanitizer_common/sanitizer_flags.h" |
| 23 | #include "sanitizer_common/sanitizer_win_interception.h" |
| 24 | #include "ubsan/ubsan_flags.h" |
| 25 | #include "ubsan/ubsan_platform.h" |
| 26 | |
| 27 | namespace __asan { |
| 28 | |
| 29 | Flags asan_flags_dont_use_directly; // use via flags(). |
| 30 | |
| 31 | static const char *MaybeUseAsanDefaultOptionsCompileDefinition() { |
| 32 | #ifdef ASAN_DEFAULT_OPTIONS |
| 33 | return SANITIZER_STRINGIFY(ASAN_DEFAULT_OPTIONS); |
| 34 | #else |
| 35 | return "" ; |
| 36 | #endif |
| 37 | } |
| 38 | |
| 39 | void Flags::SetDefaults() { |
| 40 | #define ASAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; |
| 41 | #include "asan_flags.inc" |
| 42 | #undef ASAN_FLAG |
| 43 | } |
| 44 | |
| 45 | static void RegisterAsanFlags(FlagParser *parser, Flags *f) { |
| 46 | #define ASAN_FLAG(Type, Name, DefaultValue, Description) \ |
| 47 | RegisterFlag(parser, #Name, Description, &f->Name); |
| 48 | #include "asan_flags.inc" |
| 49 | #undef ASAN_FLAG |
| 50 | } |
| 51 | |
| 52 | static void DisplayHelpMessages(FlagParser *parser) { |
| 53 | // TODO(eugenis): dump all flags at verbosity>=2? |
| 54 | if (Verbosity()) { |
| 55 | ReportUnrecognizedFlags(); |
| 56 | } |
| 57 | |
| 58 | if (common_flags()->help) { |
| 59 | parser->PrintFlagDescriptions(); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | static void InitializeDefaultFlags() { |
| 64 | Flags *f = flags(); |
| 65 | FlagParser asan_parser; |
| 66 | |
| 67 | // Set the default values and prepare for parsing ASan and common flags. |
| 68 | SetCommonFlagsDefaults(); |
| 69 | { |
| 70 | CommonFlags cf; |
| 71 | cf.CopyFrom(other: *common_flags()); |
| 72 | cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS; |
| 73 | cf.external_symbolizer_path = GetEnv(name: "ASAN_SYMBOLIZER_PATH" ); |
| 74 | cf.malloc_context_size = kDefaultMallocContextSize; |
| 75 | cf.intercept_tls_get_addr = true; |
| 76 | cf.exitcode = 1; |
| 77 | OverrideCommonFlags(cf); |
| 78 | } |
| 79 | f->SetDefaults(); |
| 80 | |
| 81 | RegisterAsanFlags(parser: &asan_parser, f); |
| 82 | RegisterCommonFlags(parser: &asan_parser); |
| 83 | |
| 84 | // Set the default values and prepare for parsing LSan and UBSan flags |
| 85 | // (which can also overwrite common flags). |
| 86 | #if CAN_SANITIZE_LEAKS |
| 87 | __lsan::Flags *lf = __lsan::flags(); |
| 88 | lf->SetDefaults(); |
| 89 | |
| 90 | FlagParser lsan_parser; |
| 91 | __lsan::RegisterLsanFlags(parser: &lsan_parser, f: lf); |
| 92 | RegisterCommonFlags(parser: &lsan_parser); |
| 93 | #endif |
| 94 | |
| 95 | #if CAN_SANITIZE_UB |
| 96 | __ubsan::Flags *uf = __ubsan::flags(); |
| 97 | uf->SetDefaults(); |
| 98 | |
| 99 | FlagParser ubsan_parser; |
| 100 | __ubsan::RegisterUbsanFlags(parser: &ubsan_parser, f: uf); |
| 101 | RegisterCommonFlags(parser: &ubsan_parser); |
| 102 | #endif |
| 103 | |
| 104 | if (SANITIZER_APPLE) { |
| 105 | // Support macOS MallocScribble and MallocPreScribble: |
| 106 | // <https://developer.apple.com/library/content/documentation/Performance/ |
| 107 | // Conceptual/ManagingMemory/Articles/MallocDebug.html> |
| 108 | if (GetEnv(name: "MallocScribble" )) { |
| 109 | f->max_free_fill_size = 0x1000; |
| 110 | } |
| 111 | if (GetEnv(name: "MallocPreScribble" )) { |
| 112 | f->malloc_fill_byte = 0xaa; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | // Override from ASan compile definition. |
| 117 | const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); |
| 118 | asan_parser.ParseString(s: asan_compile_def); |
| 119 | |
| 120 | // Override from user-specified string. |
| 121 | const char *asan_default_options = __asan_default_options(); |
| 122 | asan_parser.ParseString(s: asan_default_options); |
| 123 | #if CAN_SANITIZE_UB |
| 124 | const char *ubsan_default_options = __ubsan_default_options(); |
| 125 | ubsan_parser.ParseString(s: ubsan_default_options); |
| 126 | #endif |
| 127 | #if CAN_SANITIZE_LEAKS |
| 128 | const char *lsan_default_options = __lsan_default_options(); |
| 129 | lsan_parser.ParseString(s: lsan_default_options); |
| 130 | #endif |
| 131 | |
| 132 | // Override from command line. |
| 133 | asan_parser.ParseStringFromEnv(env_name: "ASAN_OPTIONS" ); |
| 134 | #if CAN_SANITIZE_LEAKS |
| 135 | lsan_parser.ParseStringFromEnv(env_name: "LSAN_OPTIONS" ); |
| 136 | #endif |
| 137 | #if CAN_SANITIZE_UB |
| 138 | ubsan_parser.ParseStringFromEnv(env_name: "UBSAN_OPTIONS" ); |
| 139 | #endif |
| 140 | |
| 141 | InitializeCommonFlags(); |
| 142 | |
| 143 | // TODO(samsonov): print all of the flags (ASan, LSan, common). |
| 144 | DisplayHelpMessages(parser: &asan_parser); |
| 145 | } |
| 146 | |
| 147 | // Validate flags and report incompatible configurations |
| 148 | static void ProcessFlags() { |
| 149 | Flags *f = flags(); |
| 150 | |
| 151 | // Flag validation: |
| 152 | if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { |
| 153 | Report(format: "%s: detect_leaks is not supported on this platform.\n" , |
| 154 | SanitizerToolName); |
| 155 | Die(); |
| 156 | } |
| 157 | // Ensure that redzone is at least ASAN_SHADOW_GRANULARITY. |
| 158 | if (f->redzone < (int)ASAN_SHADOW_GRANULARITY) |
| 159 | f->redzone = ASAN_SHADOW_GRANULARITY; |
| 160 | // Make "strict_init_order" imply "check_initialization_order". |
| 161 | // TODO(samsonov): Use a single runtime flag for an init-order checker. |
| 162 | if (f->strict_init_order) { |
| 163 | f->check_initialization_order = true; |
| 164 | } |
| 165 | CHECK_LE((uptr)common_flags()->malloc_context_size, kStackTraceMax); |
| 166 | CHECK_LE(f->min_uar_stack_size_log, f->max_uar_stack_size_log); |
| 167 | CHECK_GE(f->redzone, 16); |
| 168 | CHECK_GE(f->max_redzone, f->redzone); |
| 169 | CHECK_LE(f->max_redzone, 2048); |
| 170 | CHECK(IsPowerOfTwo(f->redzone)); |
| 171 | CHECK(IsPowerOfTwo(f->max_redzone)); |
| 172 | |
| 173 | // quarantine_size is deprecated but we still honor it. |
| 174 | // quarantine_size can not be used together with quarantine_size_mb. |
| 175 | if (f->quarantine_size >= 0 && f->quarantine_size_mb >= 0) { |
| 176 | Report(format: "%s: please use either 'quarantine_size' (deprecated) or " |
| 177 | "quarantine_size_mb, but not both\n" , SanitizerToolName); |
| 178 | Die(); |
| 179 | } |
| 180 | if (f->quarantine_size >= 0) |
| 181 | f->quarantine_size_mb = f->quarantine_size >> 20; |
| 182 | if (f->quarantine_size_mb < 0) { |
| 183 | const int kDefaultQuarantineSizeMb = |
| 184 | (ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8; |
| 185 | f->quarantine_size_mb = kDefaultQuarantineSizeMb; |
| 186 | } |
| 187 | if (f->thread_local_quarantine_size_kb < 0) { |
| 188 | const u32 kDefaultThreadLocalQuarantineSizeKb = |
| 189 | // It is not advised to go lower than 64Kb, otherwise quarantine batches |
| 190 | // pushed from thread local quarantine to global one will create too |
| 191 | // much overhead. One quarantine batch size is 8Kb and it holds up to |
| 192 | // 1021 chunk, which amounts to 1/8 memory overhead per batch when |
| 193 | // thread local quarantine is set to 64Kb. |
| 194 | (ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10); |
| 195 | f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb; |
| 196 | } |
| 197 | if (f->thread_local_quarantine_size_kb == 0 && f->quarantine_size_mb > 0) { |
| 198 | Report(format: "%s: thread_local_quarantine_size_kb can be set to 0 only when " |
| 199 | "quarantine_size_mb is set to 0\n" , SanitizerToolName); |
| 200 | Die(); |
| 201 | } |
| 202 | if (!f->replace_str && common_flags()->intercept_strlen) { |
| 203 | Report(format: "WARNING: strlen interceptor is enabled even though replace_str=0. " |
| 204 | "Use intercept_strlen=0 to disable it." ); |
| 205 | } |
| 206 | if (!f->replace_str && common_flags()->intercept_strchr) { |
| 207 | Report(format: "WARNING: strchr* interceptors are enabled even though " |
| 208 | "replace_str=0. Use intercept_strchr=0 to disable them." ); |
| 209 | } |
| 210 | if (!f->replace_str && common_flags()->intercept_strndup) { |
| 211 | Report(format: "WARNING: strndup* interceptors are enabled even though " |
| 212 | "replace_str=0. Use intercept_strndup=0 to disable them." ); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | void InitializeFlags() { |
| 217 | InitializeDefaultFlags(); |
| 218 | ProcessFlags(); |
| 219 | |
| 220 | #if SANITIZER_WINDOWS |
| 221 | // On Windows, weak symbols (such as the `__asan_default_options` function) |
| 222 | // are emulated by having the user program register which weak functions are |
| 223 | // defined. The ASAN DLL will initialize flags prior to user module |
| 224 | // initialization, so __asan_default_options will not point to the user |
| 225 | // definition yet. We still want to ensure we capture when options are passed |
| 226 | // via |
| 227 | // __asan_default_options, so we add a callback to be run |
| 228 | // when it is registered with the runtime. |
| 229 | |
| 230 | // There is theoretically time between the initial ProcessFlags and |
| 231 | // registering the weak callback where a weak function could be added and we |
| 232 | // would miss it, but in practice, InitializeFlags will always happen under |
| 233 | // the loader lock (if built as a DLL) and so will any calls to |
| 234 | // __sanitizer_register_weak_function. |
| 235 | AddRegisterWeakFunctionCallback( |
| 236 | reinterpret_cast<uptr>(__asan_default_options), []() { |
| 237 | // We call `InitializeDefaultFlags` again, instead of just parsing |
| 238 | // `__asan_default_options` directly, to ensure that flags set through |
| 239 | // `ASAN_OPTS` take precedence over those set through |
| 240 | // `__asan_default_options`. |
| 241 | InitializeDefaultFlags(); |
| 242 | ProcessFlags(); |
| 243 | ApplyFlags(); |
| 244 | }); |
| 245 | |
| 246 | # if CAN_SANITIZE_UB |
| 247 | AddRegisterWeakFunctionCallback( |
| 248 | reinterpret_cast<uptr>(__ubsan_default_options), []() { |
| 249 | FlagParser ubsan_parser; |
| 250 | |
| 251 | __ubsan::RegisterUbsanFlags(&ubsan_parser, __ubsan::flags()); |
| 252 | RegisterCommonFlags(&ubsan_parser); |
| 253 | ubsan_parser.ParseString(__ubsan_default_options()); |
| 254 | |
| 255 | // To match normal behavior, do not print UBSan help. |
| 256 | ProcessFlags(); |
| 257 | }); |
| 258 | # endif |
| 259 | |
| 260 | # if CAN_SANITIZE_LEAKS |
| 261 | AddRegisterWeakFunctionCallback( |
| 262 | reinterpret_cast<uptr>(__lsan_default_options), []() { |
| 263 | FlagParser lsan_parser; |
| 264 | |
| 265 | __lsan::RegisterLsanFlags(&lsan_parser, __lsan::flags()); |
| 266 | RegisterCommonFlags(&lsan_parser); |
| 267 | lsan_parser.ParseString(__lsan_default_options()); |
| 268 | |
| 269 | // To match normal behavior, do not print LSan help. |
| 270 | ProcessFlags(); |
| 271 | }); |
| 272 | # endif |
| 273 | |
| 274 | #endif |
| 275 | } |
| 276 | |
| 277 | } // namespace __asan |
| 278 | |
| 279 | SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) { |
| 280 | return "" ; |
| 281 | } |
| 282 | |