1 //===-- sanitizer_flags.cc ------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_flags.h"
14 #include "sanitizer_common.h"
15 #include "sanitizer_libc.h"
16 #include "sanitizer_list.h"
18 namespace __sanitizer
{
20 CommonFlags common_flags_dont_use
;
22 struct FlagDescription
{
24 const char *description
;
25 FlagDescription
*next
;
28 IntrusiveList
<FlagDescription
> flag_descriptions
;
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
35 void SetCommonFlagsDefaults(CommonFlags
*f
) {
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";
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;
59 f
->legacy_pthread_cond
= false;
60 f
->intercept_tls_get_addr
= false;
62 f
->coverage_direct
= SANITIZER_ANDROID
;
63 f
->coverage_dir
= ".";
64 f
->full_address_space
= false;
66 f
->print_suppressions
= true;
67 f
->disable_coredump
= (SANITIZER_WORDSIZE
== 64);
68 f
->symbolize_inline_frames
= true;
69 f
->stack_trace_format
= "DEFAULT";
72 void 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 "
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 "
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 "
91 ParseFlag(str
, &f
->fast_unwind_on_malloc
, "fast_unwind_on_malloc",
92 "If available, use the fast frame-pointer-based unwinder on "
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 "
112 ParseFlag(str
, &f
->print_summary
, "print_summary",
113 "If false, disable printing error summaries in addition to error "
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 "
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 "
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 "
148 ParseFlag(str
, &f
->coverage_dir
, "coverage_dir",
149 "Target directory for coverage dumps. Defaults to the current "
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.");
168 // Do a sanity check for certain flags.
169 if (f
->malloc_context_size
< 1)
170 f
->malloc_context_size
= 1;
173 static bool GetFlagValue(const char *env
, const char *name
,
174 const char **value
, int *value_length
) {
179 pos
= internal_strstr(env
, name
);
182 const char *name_end
= pos
+ internal_strlen(name
);
184 ((pos
[-1] >= 'a' && pos
[-1] <= 'z') || pos
[-1] == '_')) ||
186 // Seems to be middle of another flag name or value.
200 end
= internal_strchr(pos
, '"');
201 } else if (pos
[0] == '\'') {
203 end
= internal_strchr(pos
, '\'');
205 // Read until the next space or colon.
206 end
= pos
+ internal_strcspn(pos
, " :");
209 end
= pos
+ internal_strlen(pos
);
212 *value_length
= end
- pos
;
216 static bool StartsWith(const char *flag
, int flag_length
, const char *value
) {
219 int value_length
= internal_strlen(value
);
220 return (flag_length
>= value_length
) &&
221 (0 == internal_strncmp(flag
, value
, value_length
));
224 static LowLevelAllocator allocator_for_flags
;
226 // The linear scan is suboptimal, but the number of flags is relatively small.
227 bool 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;
235 void 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
);
243 // TODO(glider): put the descriptions inside CommonFlags.
244 void 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
);
253 void ParseFlag(const char *env
, bool *flag
,
254 const char *name
, const char *descr
) {
257 AddFlagDescription(name
, descr
);
258 if (!GetFlagValue(env
, name
, &value
, &value_length
))
260 if (StartsWith(value
, value_length
, "0") ||
261 StartsWith(value
, value_length
, "no") ||
262 StartsWith(value
, value_length
, "false"))
264 if (StartsWith(value
, value_length
, "1") ||
265 StartsWith(value
, value_length
, "yes") ||
266 StartsWith(value
, value_length
, "true"))
270 void ParseFlag(const char *env
, int *flag
,
271 const char *name
, const char *descr
) {
274 AddFlagDescription(name
, descr
);
275 if (!GetFlagValue(env
, name
, &value
, &value_length
))
277 *flag
= static_cast<int>(internal_atoll(value
));
280 void ParseFlag(const char *env
, uptr
*flag
,
281 const char *name
, const char *descr
) {
284 AddFlagDescription(name
, descr
);
285 if (!GetFlagValue(env
, name
, &value
, &value_length
))
287 *flag
= static_cast<uptr
>(internal_atoll(value
));
290 void ParseFlag(const char *env
, const char **flag
,
291 const char *name
, const char *descr
) {
294 AddFlagDescription(name
, descr
);
295 if (!GetFlagValue(env
, name
, &value
, &value_length
))
297 // Copy the flag value. Don't use locks here, as flags are parsed at
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';
305 } // namespace __sanitizer