1 //===-- sanitizer_flags.cc ------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_flags.h" 15 16 #include "sanitizer_common.h" 17 #include "sanitizer_libc.h" 18 #include "sanitizer_list.h" 19 20 namespace __sanitizer { 21 22 CommonFlags common_flags_dont_use; 23 24 struct FlagDescription { 25 const char *name; 26 const char *description; 27 FlagDescription *next; 28 }; 29 30 IntrusiveList<FlagDescription> flag_descriptions; 31 32 // If set, the tool will install its own SEGV signal handler by default. 33 #ifndef SANITIZER_NEEDS_SEGV 34 # define SANITIZER_NEEDS_SEGV 1 35 #endif 36 37 void SetCommonFlagsDefaults(CommonFlags *f) { 38 f->symbolize = true; 39 f->external_symbolizer_path = 0; 40 f->allow_addr2line = false; 41 f->strip_path_prefix = ""; 42 f->fast_unwind_on_fatal = false; 43 f->fast_unwind_on_malloc = true; 44 f->handle_ioctl = false; 45 f->malloc_context_size = 1; 46 f->log_path = "stderr"; 47 f->verbosity = 0; 48 f->detect_leaks = true; 49 f->leak_check_at_exit = true; 50 f->allocator_may_return_null = false; 51 f->print_summary = true; 52 f->check_printf = true; 53 // TODO(glider): tools may want to set different defaults for handle_segv. 54 f->handle_segv = SANITIZER_NEEDS_SEGV; 55 f->allow_user_segv_handler = false; 56 f->use_sigaltstack = true; 57 f->detect_deadlocks = false; 58 f->clear_shadow_mmap_threshold = 64 * 1024; 59 f->color = "auto"; 60 f->legacy_pthread_cond = false; 61 f->intercept_tls_get_addr = false; 62 f->coverage = false; 63 f->coverage_direct = SANITIZER_ANDROID; 64 f->coverage_dir = "."; 65 f->full_address_space = false; 66 } 67 68 void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { 69 ParseFlag(str, &f->symbolize, "symbolize", 70 "If set, use the online symbolizer from common sanitizer runtime to turn " 71 "virtual addresses to file/line locations."); 72 ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path", 73 "Path to external symbolizer. If empty, the tool will search $PATH for " 74 "the symbolizer."); 75 ParseFlag(str, &f->allow_addr2line, "allow_addr2line", 76 "If set, allows online symbolizer to run addr2line binary to symbolize " 77 "stack traces (addr2line will only be used if llvm-symbolizer binary is " 78 "unavailable."); 79 ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix", 80 "Strips this prefix from file paths in error reports."); 81 ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal", 82 "If available, use the fast frame-pointer-based unwinder on fatal " 83 "errors."); 84 ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc", 85 "If available, use the fast frame-pointer-based unwinder on " 86 "malloc/free."); 87 ParseFlag(str, &f->handle_ioctl, "handle_ioctl", 88 "Intercept and handle ioctl requests."); 89 ParseFlag(str, &f->malloc_context_size, "malloc_context_size", 90 "Max number of stack frames kept for each allocation/deallocation."); 91 ParseFlag(str, &f->log_path, "log_path", 92 "Write logs to \"log_path.pid\". The special values are \"stdout\" and " 93 "\"stderr\". The default is \"stderr\"."); 94 ParseFlag(str, &f->verbosity, "verbosity", 95 "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output)."); 96 ParseFlag(str, &f->detect_leaks, "detect_leaks", 97 "Enable memory leak detection."); 98 ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit", 99 "Invoke leak checking in an atexit handler. Has no effect if " 100 "detect_leaks=false, or if __lsan_do_leak_check() is called before the " 101 "handler has a chance to run."); 102 ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null", 103 "If false, the allocator will crash instead of returning 0 on " 104 "out-of-memory."); 105 ParseFlag(str, &f->print_summary, "print_summary", 106 "If false, disable printing error summaries in addition to error " 107 "reports."); 108 ParseFlag(str, &f->check_printf, "check_printf", 109 "Check printf arguments."); 110 ParseFlag(str, &f->handle_segv, "handle_segv", 111 "If set, registers the tool's custom SEGV handler (both SIGBUS and " 112 "SIGSEGV on OSX)."); 113 ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler", 114 "If set, allows user to register a SEGV handler even if the tool " 115 "registers one."); 116 ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack", 117 "If set, uses alternate stack for signal handling."); 118 ParseFlag(str, &f->detect_deadlocks, "detect_deadlocks", 119 "If set, deadlock detection is enabled."); 120 ParseFlag(str, &f->clear_shadow_mmap_threshold, 121 "clear_shadow_mmap_threshold", 122 "Large shadow regions are zero-filled using mmap(NORESERVE) instead of " 123 "memset(). This is the threshold size in bytes."); 124 ParseFlag(str, &f->color, "color", 125 "Colorize reports: (always|never|auto)."); 126 ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond", 127 "Enables support for dynamic libraries linked with libpthread 2.2.5."); 128 ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr", 129 "Intercept __tls_get_addr."); 130 ParseFlag(str, &f->help, "help", "Print the flag descriptions."); 131 ParseFlag(str, &f->mmap_limit_mb, "mmap_limit_mb", 132 "Limit the amount of mmap-ed memory (excluding shadow) in Mb; " 133 "not a user-facing flag, used mosly for testing the tools"); 134 ParseFlag(str, &f->coverage, "coverage", 135 "If set, coverage information will be dumped at program shutdown (if the " 136 "coverage instrumentation was enabled at compile time)."); 137 ParseFlag(str, &f->coverage_direct, "coverage_direct", 138 "If set, coverage information will be dumped directly to a memory " 139 "mapped file. This way data is not lost even if the process is " 140 "suddenly killed."); 141 ParseFlag(str, &f->coverage_dir, "coverage_dir", 142 "Target directory for coverage dumps. Defaults to the current " 143 "directory."); 144 ParseFlag(str, &f->full_address_space, "full_address_space", 145 "Sanitize complete address space; " 146 "by default kernel area on 32-bit platforms will not be sanitized"); 147 148 // Do a sanity check for certain flags. 149 if (f->malloc_context_size < 1) 150 f->malloc_context_size = 1; 151 } 152 153 static bool GetFlagValue(const char *env, const char *name, 154 const char **value, int *value_length) { 155 if (env == 0) 156 return false; 157 const char *pos = 0; 158 for (;;) { 159 pos = internal_strstr(env, name); 160 if (pos == 0) 161 return false; 162 const char *name_end = pos + internal_strlen(name); 163 if ((pos != env && 164 ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) || 165 *name_end != '=') { 166 // Seems to be middle of another flag name or value. 167 env = pos + 1; 168 continue; 169 } 170 pos = name_end; 171 break; 172 } 173 const char *end; 174 if (pos[0] != '=') { 175 end = pos; 176 } else { 177 pos += 1; 178 if (pos[0] == '"') { 179 pos += 1; 180 end = internal_strchr(pos, '"'); 181 } else if (pos[0] == '\'') { 182 pos += 1; 183 end = internal_strchr(pos, '\''); 184 } else { 185 // Read until the next space or colon. 186 end = pos + internal_strcspn(pos, " :"); 187 } 188 if (end == 0) 189 end = pos + internal_strlen(pos); 190 } 191 *value = pos; 192 *value_length = end - pos; 193 return true; 194 } 195 196 static bool StartsWith(const char *flag, int flag_length, const char *value) { 197 if (!flag || !value) 198 return false; 199 int value_length = internal_strlen(value); 200 return (flag_length >= value_length) && 201 (0 == internal_strncmp(flag, value, value_length)); 202 } 203 204 static LowLevelAllocator allocator_for_flags; 205 206 // The linear scan is suboptimal, but the number of flags is relatively small. 207 bool FlagInDescriptionList(const char *name) { 208 IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions); 209 while (it.hasNext()) { 210 if (!internal_strcmp(it.next()->name, name)) return true; 211 } 212 return false; 213 } 214 215 void AddFlagDescription(const char *name, const char *description) { 216 if (FlagInDescriptionList(name)) return; 217 FlagDescription *new_description = new(allocator_for_flags) FlagDescription; 218 new_description->name = name; 219 new_description->description = description; 220 flag_descriptions.push_back(new_description); 221 } 222 223 // TODO(glider): put the descriptions inside CommonFlags. 224 void PrintFlagDescriptions() { 225 IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions); 226 Printf("Available flags for %s:\n", SanitizerToolName); 227 while (it.hasNext()) { 228 FlagDescription *descr = it.next(); 229 Printf("\t%s\n\t\t- %s\n", descr->name, descr->description); 230 } 231 } 232 233 void ParseFlag(const char *env, bool *flag, 234 const char *name, const char *descr) { 235 const char *value; 236 int value_length; 237 AddFlagDescription(name, descr); 238 if (!GetFlagValue(env, name, &value, &value_length)) 239 return; 240 if (StartsWith(value, value_length, "0") || 241 StartsWith(value, value_length, "no") || 242 StartsWith(value, value_length, "false")) 243 *flag = false; 244 if (StartsWith(value, value_length, "1") || 245 StartsWith(value, value_length, "yes") || 246 StartsWith(value, value_length, "true")) 247 *flag = true; 248 } 249 250 void ParseFlag(const char *env, int *flag, 251 const char *name, const char *descr) { 252 const char *value; 253 int value_length; 254 AddFlagDescription(name, descr); 255 if (!GetFlagValue(env, name, &value, &value_length)) 256 return; 257 *flag = static_cast<int>(internal_atoll(value)); 258 } 259 260 void ParseFlag(const char *env, uptr *flag, 261 const char *name, const char *descr) { 262 const char *value; 263 int value_length; 264 AddFlagDescription(name, descr); 265 if (!GetFlagValue(env, name, &value, &value_length)) 266 return; 267 *flag = static_cast<uptr>(internal_atoll(value)); 268 } 269 270 void ParseFlag(const char *env, const char **flag, 271 const char *name, const char *descr) { 272 const char *value; 273 int value_length; 274 AddFlagDescription(name, descr); 275 if (!GetFlagValue(env, name, &value, &value_length)) 276 return; 277 // Copy the flag value. Don't use locks here, as flags are parsed at 278 // tool startup. 279 char *value_copy = (char*)(allocator_for_flags.Allocate(value_length + 1)); 280 internal_memcpy(value_copy, value, value_length); 281 value_copy[value_length] = '\0'; 282 *flag = value_copy; 283 } 284 285 } // namespace __sanitizer 286