Home | History | Annotate | Download | only in sanitizer_common
      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