diff options
Diffstat (limited to 'lib/sanitizer_common/sanitizer_flags.cc')
-rw-r--r-- | lib/sanitizer_common/sanitizer_flags.cc | 294 |
1 files changed, 37 insertions, 257 deletions
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc index 40b6ec067150e..a2965351cf2ab 100644 --- a/lib/sanitizer_common/sanitizer_flags.cc +++ b/lib/sanitizer_common/sanitizer_flags.cc @@ -16,6 +16,7 @@ #include "sanitizer_common.h" #include "sanitizer_libc.h" #include "sanitizer_list.h" +#include "sanitizer_flag_parser.h" namespace __sanitizer { @@ -34,274 +35,53 @@ IntrusiveList<FlagDescription> flag_descriptions; # define SANITIZER_NEEDS_SEGV 1 #endif -void SetCommonFlagsDefaults(CommonFlags *f) { - f->symbolize = true; - f->external_symbolizer_path = 0; - f->allow_addr2line = false; - f->strip_path_prefix = ""; - f->fast_unwind_on_check = false; - f->fast_unwind_on_fatal = false; - f->fast_unwind_on_malloc = true; - f->handle_ioctl = false; - f->malloc_context_size = 1; - f->log_path = "stderr"; - f->verbosity = 0; - f->detect_leaks = true; - f->leak_check_at_exit = true; - f->allocator_may_return_null = false; - f->print_summary = true; - f->check_printf = true; - // TODO(glider): tools may want to set different defaults for handle_segv. - f->handle_segv = SANITIZER_NEEDS_SEGV; - f->allow_user_segv_handler = false; - f->use_sigaltstack = true; - f->detect_deadlocks = false; - f->clear_shadow_mmap_threshold = 64 * 1024; - f->color = "auto"; - f->legacy_pthread_cond = false; - f->intercept_tls_get_addr = false; - f->coverage = false; - f->coverage_direct = SANITIZER_ANDROID; - f->coverage_dir = "."; - f->full_address_space = false; - f->suppressions = ""; - f->print_suppressions = true; - f->disable_coredump = (SANITIZER_WORDSIZE == 64); - f->symbolize_inline_frames = true; - f->stack_trace_format = "DEFAULT"; +void CommonFlags::SetDefaults() { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "sanitizer_flags.inc" +#undef COMMON_FLAG } -void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { - ParseFlag(str, &f->symbolize, "symbolize", - "If set, use the online symbolizer from common sanitizer runtime to turn " - "virtual addresses to file/line locations."); - ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path", - "Path to external symbolizer. If empty, the tool will search $PATH for " - "the symbolizer."); - ParseFlag(str, &f->allow_addr2line, "allow_addr2line", - "If set, allows online symbolizer to run addr2line binary to symbolize " - "stack traces (addr2line will only be used if llvm-symbolizer binary is " - "unavailable."); - ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix", - "Strips this prefix from file paths in error reports."); - ParseFlag(str, &f->fast_unwind_on_check, "fast_unwind_on_check", - "If available, use the fast frame-pointer-based unwinder on " - "internal CHECK failures."); - ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal", - "If available, use the fast frame-pointer-based unwinder on fatal " - "errors."); - ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc", - "If available, use the fast frame-pointer-based unwinder on " - "malloc/free."); - ParseFlag(str, &f->handle_ioctl, "handle_ioctl", - "Intercept and handle ioctl requests."); - ParseFlag(str, &f->malloc_context_size, "malloc_context_size", - "Max number of stack frames kept for each allocation/deallocation."); - ParseFlag(str, &f->log_path, "log_path", - "Write logs to \"log_path.pid\". The special values are \"stdout\" and " - "\"stderr\". The default is \"stderr\"."); - ParseFlag(str, &f->verbosity, "verbosity", - "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output)."); - ParseFlag(str, &f->detect_leaks, "detect_leaks", - "Enable memory leak detection."); - ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit", - "Invoke leak checking in an atexit handler. Has no effect if " - "detect_leaks=false, or if __lsan_do_leak_check() is called before the " - "handler has a chance to run."); - ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null", - "If false, the allocator will crash instead of returning 0 on " - "out-of-memory."); - ParseFlag(str, &f->print_summary, "print_summary", - "If false, disable printing error summaries in addition to error " - "reports."); - ParseFlag(str, &f->check_printf, "check_printf", - "Check printf arguments."); - ParseFlag(str, &f->handle_segv, "handle_segv", - "If set, registers the tool's custom SEGV handler (both SIGBUS and " - "SIGSEGV on OSX)."); - ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler", - "If set, allows user to register a SEGV handler even if the tool " - "registers one."); - ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack", - "If set, uses alternate stack for signal handling."); - ParseFlag(str, &f->detect_deadlocks, "detect_deadlocks", - "If set, deadlock detection is enabled."); - ParseFlag(str, &f->clear_shadow_mmap_threshold, - "clear_shadow_mmap_threshold", - "Large shadow regions are zero-filled using mmap(NORESERVE) instead of " - "memset(). This is the threshold size in bytes."); - ParseFlag(str, &f->color, "color", - "Colorize reports: (always|never|auto)."); - ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond", - "Enables support for dynamic libraries linked with libpthread 2.2.5."); - ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr", - "Intercept __tls_get_addr."); - ParseFlag(str, &f->help, "help", "Print the flag descriptions."); - ParseFlag(str, &f->mmap_limit_mb, "mmap_limit_mb", - "Limit the amount of mmap-ed memory (excluding shadow) in Mb; " - "not a user-facing flag, used mosly for testing the tools"); - ParseFlag(str, &f->coverage, "coverage", - "If set, coverage information will be dumped at program shutdown (if the " - "coverage instrumentation was enabled at compile time)."); - ParseFlag(str, &f->coverage_direct, "coverage_direct", - "If set, coverage information will be dumped directly to a memory " - "mapped file. This way data is not lost even if the process is " - "suddenly killed."); - ParseFlag(str, &f->coverage_dir, "coverage_dir", - "Target directory for coverage dumps. Defaults to the current " - "directory."); - ParseFlag(str, &f->full_address_space, "full_address_space", - "Sanitize complete address space; " - "by default kernel area on 32-bit platforms will not be sanitized"); - ParseFlag(str, &f->suppressions, "suppressions", "Suppressions file name."); - ParseFlag(str, &f->print_suppressions, "print_suppressions", - "Print matched suppressions at exit."); - ParseFlag(str, &f->disable_coredump, "disable_coredump", - "Disable core dumping. By default, disable_core=1 on 64-bit to avoid " - "dumping a 16T+ core file. Ignored on OSes that don't dump core by" - "default and for sanitizers that don't reserve lots of virtual memory."); - ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames", - "Print inlined frames in stacktraces. Defaults to true."); - ParseFlag(str, &f->stack_trace_format, "stack_trace_format", - "Format string used to render stack frames. " - "See sanitizer_stacktrace_printer.h for the format description. " - "Use DEFAULT to get default format."); - - // Do a sanity check for certain flags. - if (f->malloc_context_size < 1) - f->malloc_context_size = 1; +void CommonFlags::CopyFrom(const CommonFlags &other) { + internal_memcpy(this, &other, sizeof(*this)); } -static bool GetFlagValue(const char *env, const char *name, - const char **value, int *value_length) { - if (env == 0) - return false; - const char *pos = 0; - for (;;) { - pos = internal_strstr(env, name); - if (pos == 0) +class FlagHandlerInclude : public FlagHandlerBase { + static const uptr kMaxIncludeSize = 1 << 15; + FlagParser *parser_; + + public: + explicit FlagHandlerInclude(FlagParser *parser) : parser_(parser) {} + bool Parse(const char *value) { + char *data; + uptr data_mapped_size; + int err; + uptr len = + ReadFileToBuffer(value, &data, &data_mapped_size, + Max(kMaxIncludeSize, GetPageSizeCached()), &err); + if (!len) { + Printf("Failed to read options from '%s': error %d\n", value, err); return false; - const char *name_end = pos + internal_strlen(name); - if ((pos != env && - ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) || - *name_end != '=') { - // Seems to be middle of another flag name or value. - env = pos + 1; - continue; - } - pos = name_end; - break; - } - const char *end; - if (pos[0] != '=') { - end = pos; - } else { - pos += 1; - if (pos[0] == '"') { - pos += 1; - end = internal_strchr(pos, '"'); - } else if (pos[0] == '\'') { - pos += 1; - end = internal_strchr(pos, '\''); - } else { - // Read until the next space or colon. - end = pos + internal_strcspn(pos, " :"); } - if (end == 0) - end = pos + internal_strlen(pos); - } - *value = pos; - *value_length = end - pos; - return true; -} - -static bool StartsWith(const char *flag, int flag_length, const char *value) { - if (!flag || !value) - return false; - int value_length = internal_strlen(value); - return (flag_length >= value_length) && - (0 == internal_strncmp(flag, value, value_length)); -} - -static LowLevelAllocator allocator_for_flags; - -// The linear scan is suboptimal, but the number of flags is relatively small. -bool FlagInDescriptionList(const char *name) { - IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions); - while (it.hasNext()) { - if (!internal_strcmp(it.next()->name, name)) return true; + parser_->ParseString(data); + UnmapOrDie(data, data_mapped_size); + return true; } - return false; -} - -void AddFlagDescription(const char *name, const char *description) { - if (FlagInDescriptionList(name)) return; - FlagDescription *new_description = new(allocator_for_flags) FlagDescription; - new_description->name = name; - new_description->description = description; - flag_descriptions.push_back(new_description); -} - -// TODO(glider): put the descriptions inside CommonFlags. -void PrintFlagDescriptions() { - IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions); - Printf("Available flags for %s:\n", SanitizerToolName); - while (it.hasNext()) { - FlagDescription *descr = it.next(); - Printf("\t%s\n\t\t- %s\n", descr->name, descr->description); - } -} - -void ParseFlag(const char *env, bool *flag, - const char *name, const char *descr) { - const char *value; - int value_length; - AddFlagDescription(name, descr); - if (!GetFlagValue(env, name, &value, &value_length)) - return; - if (StartsWith(value, value_length, "0") || - StartsWith(value, value_length, "no") || - StartsWith(value, value_length, "false")) - *flag = false; - if (StartsWith(value, value_length, "1") || - StartsWith(value, value_length, "yes") || - StartsWith(value, value_length, "true")) - *flag = true; -} +}; -void ParseFlag(const char *env, int *flag, - const char *name, const char *descr) { - const char *value; - int value_length; - AddFlagDescription(name, descr); - if (!GetFlagValue(env, name, &value, &value_length)) - return; - *flag = static_cast<int>(internal_atoll(value)); +void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf) { + FlagHandlerInclude *fh_include = + new (FlagParser::Alloc) FlagHandlerInclude(parser); // NOLINT + parser->RegisterHandler("include", fh_include, + "read more options from the given file"); } -void ParseFlag(const char *env, uptr *flag, - const char *name, const char *descr) { - const char *value; - int value_length; - AddFlagDescription(name, descr); - if (!GetFlagValue(env, name, &value, &value_length)) - return; - *flag = static_cast<uptr>(internal_atoll(value)); -} +void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { +#define COMMON_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(parser, #Name, Description, &cf->Name); +#include "sanitizer_flags.inc" +#undef COMMON_FLAG -void ParseFlag(const char *env, const char **flag, - const char *name, const char *descr) { - const char *value; - int value_length; - AddFlagDescription(name, descr); - if (!GetFlagValue(env, name, &value, &value_length)) - return; - // Copy the flag value. Don't use locks here, as flags are parsed at - // tool startup. - char *value_copy = (char*)(allocator_for_flags.Allocate(value_length + 1)); - internal_memcpy(value_copy, value, value_length); - value_copy[value_length] = '\0'; - *flag = value_copy; + RegisterIncludeFlag(parser, cf); } } // namespace __sanitizer |