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