| 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 | static void ProcessFlags() { |
| 148 | Flags *f = flags(); |
| 149 | |
| 150 | // Flag validation: |
| 151 | if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { |
| 152 | Report(format: "%s: detect_leaks is not supported on this platform.\n" , |
| 153 | SanitizerToolName); |
| 154 | Die(); |
| 155 | } |
| 156 | // Ensure that redzone is at least ASAN_SHADOW_GRANULARITY. |
| 157 | if (f->redzone < (int)ASAN_SHADOW_GRANULARITY) |
| 158 | f->redzone = ASAN_SHADOW_GRANULARITY; |
| 159 | // Make "strict_init_order" imply "check_initialization_order". |
| 160 | // TODO(samsonov): Use a single runtime flag for an init-order checker. |
| 161 | if (f->strict_init_order) { |
| 162 | f->check_initialization_order = true; |
| 163 | } |
| 164 | CHECK_LE((uptr)common_flags()->malloc_context_size, kStackTraceMax); |
| 165 | CHECK_LE(f->min_uar_stack_size_log, f->max_uar_stack_size_log); |
| 166 | CHECK_GE(f->redzone, 16); |
| 167 | CHECK_GE(f->max_redzone, f->redzone); |
| 168 | CHECK_LE(f->max_redzone, 2048); |
| 169 | CHECK(IsPowerOfTwo(f->redzone)); |
| 170 | CHECK(IsPowerOfTwo(f->max_redzone)); |
| 171 | |
| 172 | // quarantine_size is deprecated but we still honor it. |
| 173 | // quarantine_size can not be used together with quarantine_size_mb. |
| 174 | if (f->quarantine_size >= 0 && f->quarantine_size_mb >= 0) { |
| 175 | Report(format: "%s: please use either 'quarantine_size' (deprecated) or " |
| 176 | "quarantine_size_mb, but not both\n" , SanitizerToolName); |
| 177 | Die(); |
| 178 | } |
| 179 | if (f->quarantine_size >= 0) |
| 180 | f->quarantine_size_mb = f->quarantine_size >> 20; |
| 181 | if (f->quarantine_size_mb < 0) { |
| 182 | const int kDefaultQuarantineSizeMb = |
| 183 | (ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8; |
| 184 | f->quarantine_size_mb = kDefaultQuarantineSizeMb; |
| 185 | } |
| 186 | if (f->thread_local_quarantine_size_kb < 0) { |
| 187 | const u32 kDefaultThreadLocalQuarantineSizeKb = |
| 188 | // It is not advised to go lower than 64Kb, otherwise quarantine batches |
| 189 | // pushed from thread local quarantine to global one will create too |
| 190 | // much overhead. One quarantine batch size is 8Kb and it holds up to |
| 191 | // 1021 chunk, which amounts to 1/8 memory overhead per batch when |
| 192 | // thread local quarantine is set to 64Kb. |
| 193 | (ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10); |
| 194 | f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb; |
| 195 | } |
| 196 | if (f->thread_local_quarantine_size_kb == 0 && f->quarantine_size_mb > 0) { |
| 197 | Report(format: "%s: thread_local_quarantine_size_kb can be set to 0 only when " |
| 198 | "quarantine_size_mb is set to 0\n" , SanitizerToolName); |
| 199 | Die(); |
| 200 | } |
| 201 | if (!f->replace_str && common_flags()->intercept_strlen) { |
| 202 | Report(format: "WARNING: strlen interceptor is enabled even though replace_str=0. " |
| 203 | "Use intercept_strlen=0 to disable it." ); |
| 204 | } |
| 205 | if (!f->replace_str && common_flags()->intercept_strchr) { |
| 206 | Report(format: "WARNING: strchr* interceptors are enabled even though " |
| 207 | "replace_str=0. Use intercept_strchr=0 to disable them." ); |
| 208 | } |
| 209 | if (!f->replace_str && common_flags()->intercept_strndup) { |
| 210 | Report(format: "WARNING: strndup* interceptors are enabled even though " |
| 211 | "replace_str=0. Use intercept_strndup=0 to disable them." ); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | void InitializeFlags() { |
| 216 | InitializeDefaultFlags(); |
| 217 | ProcessFlags(); |
| 218 | |
| 219 | #if SANITIZER_WINDOWS |
| 220 | // On Windows, weak symbols are emulated by having the user program |
| 221 | // register which weak functions are defined. |
| 222 | // The ASAN DLL will initialize flags prior to user module initialization, |
| 223 | // so __asan_default_options will not point to the user definition yet. |
| 224 | // We still want to ensure we capture when options are passed via |
| 225 | // __asan_default_options, so we add a callback to be run |
| 226 | // when it is registered with the runtime. |
| 227 | |
| 228 | // There is theoretically time between the initial ProcessFlags and |
| 229 | // registering the weak callback where a weak function could be added and we |
| 230 | // would miss it, but in practice, InitializeFlags will always happen under |
| 231 | // the loader lock (if built as a DLL) and so will any calls to |
| 232 | // __sanitizer_register_weak_function. |
| 233 | AddRegisterWeakFunctionCallback( |
| 234 | reinterpret_cast<uptr>(__asan_default_options), []() { |
| 235 | FlagParser asan_parser; |
| 236 | |
| 237 | RegisterAsanFlags(&asan_parser, flags()); |
| 238 | RegisterCommonFlags(&asan_parser); |
| 239 | asan_parser.ParseString(__asan_default_options()); |
| 240 | |
| 241 | DisplayHelpMessages(&asan_parser); |
| 242 | ProcessFlags(); |
| 243 | |
| 244 | // TODO: Update other globals and data structures that may need to change |
| 245 | // after initialization due to new flags potentially being set changing after |
| 246 | // `__asan_default_options` is registered. |
| 247 | // See GH issue 'https://github.com/llvm/llvm-project/issues/117925' for |
| 248 | // details. |
| 249 | SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); |
| 250 | }); |
| 251 | |
| 252 | # if CAN_SANITIZE_UB |
| 253 | AddRegisterWeakFunctionCallback( |
| 254 | reinterpret_cast<uptr>(__ubsan_default_options), []() { |
| 255 | FlagParser ubsan_parser; |
| 256 | |
| 257 | __ubsan::RegisterUbsanFlags(&ubsan_parser, __ubsan::flags()); |
| 258 | RegisterCommonFlags(&ubsan_parser); |
| 259 | ubsan_parser.ParseString(__ubsan_default_options()); |
| 260 | |
| 261 | // To match normal behavior, do not print UBSan help. |
| 262 | ProcessFlags(); |
| 263 | }); |
| 264 | # endif |
| 265 | |
| 266 | # if CAN_SANITIZE_LEAKS |
| 267 | AddRegisterWeakFunctionCallback( |
| 268 | reinterpret_cast<uptr>(__lsan_default_options), []() { |
| 269 | FlagParser lsan_parser; |
| 270 | |
| 271 | __lsan::RegisterLsanFlags(&lsan_parser, __lsan::flags()); |
| 272 | RegisterCommonFlags(&lsan_parser); |
| 273 | lsan_parser.ParseString(__lsan_default_options()); |
| 274 | |
| 275 | // To match normal behavior, do not print LSan help. |
| 276 | ProcessFlags(); |
| 277 | }); |
| 278 | # endif |
| 279 | |
| 280 | #endif |
| 281 | } |
| 282 | |
| 283 | } // namespace __asan |
| 284 | |
| 285 | SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) { |
| 286 | return "" ; |
| 287 | } |
| 288 | |