• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetCommonFlagsDefaults(CommonFlags * f)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 
ParseCommonFlagsFromString(CommonFlags * f,const char * str)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 
GetFlagValue(const char * env,const char * name,const char ** value,int * value_length)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 
StartsWith(const char * flag,int flag_length,const char * value)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.
FlagInDescriptionList(const char * name)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 
AddFlagDescription(const char * name,const char * description)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.
PrintFlagDescriptions()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 
ParseFlag(const char * env,bool * flag,const char * name,const char * descr)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 
ParseFlag(const char * env,int * flag,const char * name,const char * descr)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 
ParseFlag(const char * env,uptr * flag,const char * name,const char * descr)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 
ParseFlag(const char * env,const char ** flag,const char * name,const char * descr)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