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
20namespace __sanitizer {
21
22CommonFlags common_flags_dont_use;
23
24struct FlagDescription {
25  const char *name;
26  const char *description;
27  FlagDescription *next;
28};
29
30IntrusiveList<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
37void 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
68void 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
153static 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
196static 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
204static LowLevelAllocator allocator_for_flags;
205
206// The linear scan is suboptimal, but the number of flags is relatively small.
207bool 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
215void 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.
224void 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
233void 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
250void 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
260void 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
270void 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