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