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(*common_flags()); 72 cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS; 73 cf.external_symbolizer_path = GetEnv("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(&asan_parser, f); 82 RegisterCommonFlags(&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(&lsan_parser, lf); 92 RegisterCommonFlags(&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(&ubsan_parser, uf); 101 RegisterCommonFlags(&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("MallocScribble")) { 109 f->max_free_fill_size = 0x1000; 110 } 111 if (GetEnv("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(asan_compile_def); 119 120 // Override from user-specified string. 121 const char *asan_default_options = __asan_default_options(); 122 asan_parser.ParseString(asan_default_options); 123 #if CAN_SANITIZE_UB 124 const char *ubsan_default_options = __ubsan_default_options(); 125 ubsan_parser.ParseString(ubsan_default_options); 126 #endif 127 #if CAN_SANITIZE_LEAKS 128 const char *lsan_default_options = __lsan_default_options(); 129 lsan_parser.ParseString(lsan_default_options); 130 #endif 131 132 // Override from command line. 133 asan_parser.ParseStringFromEnv("ASAN_OPTIONS"); 134 #if CAN_SANITIZE_LEAKS 135 lsan_parser.ParseStringFromEnv("LSAN_OPTIONS"); 136 #endif 137 #if CAN_SANITIZE_UB 138 ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS"); 139 #endif 140 141 InitializeCommonFlags(); 142 143 // TODO(samsonov): print all of the flags (ASan, LSan, common). 144 DisplayHelpMessages(&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("%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("%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("%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("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("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("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