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_fatal
= false;
41 f
->fast_unwind_on_malloc
= true;
42 f
->handle_ioctl
= false;
43 f
->malloc_context_size
= 1;
44 f
->log_path
= "stderr";
46 f
->detect_leaks
= true;
47 f
->leak_check_at_exit
= true;
48 f
->allocator_may_return_null
= false;
49 f
->print_summary
= true;
50 f
->check_printf
= true;
51 // TODO(glider): tools may want to set different defaults for handle_segv.
52 f
->handle_segv
= SANITIZER_NEEDS_SEGV
;
53 f
->allow_user_segv_handler
= false;
54 f
->use_sigaltstack
= true;
55 f
->detect_deadlocks
= false;
56 f
->clear_shadow_mmap_threshold
= 64 * 1024;
58 f
->legacy_pthread_cond
= false;
59 f
->intercept_tls_get_addr
= false;
61 f
->coverage_direct
= SANITIZER_ANDROID
;
62 f
->coverage_dir
= ".";
63 f
->full_address_space
= false;
65 f
->print_suppressions
= true;
66 f
->disable_coredump
= (SANITIZER_WORDSIZE
== 64);
69 void ParseCommonFlagsFromString(CommonFlags
*f
, const char *str
) {
70 ParseFlag(str
, &f
->symbolize
, "symbolize",
71 "If set, use the online symbolizer from common sanitizer runtime to turn "
72 "virtual addresses to file/line locations.");
73 ParseFlag(str
, &f
->external_symbolizer_path
, "external_symbolizer_path",
74 "Path to external symbolizer. If empty, the tool will search $PATH for "
76 ParseFlag(str
, &f
->allow_addr2line
, "allow_addr2line",
77 "If set, allows online symbolizer to run addr2line binary to symbolize "
78 "stack traces (addr2line will only be used if llvm-symbolizer binary is "
80 ParseFlag(str
, &f
->strip_path_prefix
, "strip_path_prefix",
81 "Strips this prefix from file paths in error reports.");
82 ParseFlag(str
, &f
->fast_unwind_on_fatal
, "fast_unwind_on_fatal",
83 "If available, use the fast frame-pointer-based unwinder on fatal "
85 ParseFlag(str
, &f
->fast_unwind_on_malloc
, "fast_unwind_on_malloc",
86 "If available, use the fast frame-pointer-based unwinder on "
88 ParseFlag(str
, &f
->handle_ioctl
, "handle_ioctl",
89 "Intercept and handle ioctl requests.");
90 ParseFlag(str
, &f
->malloc_context_size
, "malloc_context_size",
91 "Max number of stack frames kept for each allocation/deallocation.");
92 ParseFlag(str
, &f
->log_path
, "log_path",
93 "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
94 "\"stderr\". The default is \"stderr\".");
95 ParseFlag(str
, &f
->verbosity
, "verbosity",
96 "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).");
97 ParseFlag(str
, &f
->detect_leaks
, "detect_leaks",
98 "Enable memory leak detection.");
99 ParseFlag(str
, &f
->leak_check_at_exit
, "leak_check_at_exit",
100 "Invoke leak checking in an atexit handler. Has no effect if "
101 "detect_leaks=false, or if __lsan_do_leak_check() is called before the "
102 "handler has a chance to run.");
103 ParseFlag(str
, &f
->allocator_may_return_null
, "allocator_may_return_null",
104 "If false, the allocator will crash instead of returning 0 on "
106 ParseFlag(str
, &f
->print_summary
, "print_summary",
107 "If false, disable printing error summaries in addition to error "
109 ParseFlag(str
, &f
->check_printf
, "check_printf",
110 "Check printf arguments.");
111 ParseFlag(str
, &f
->handle_segv
, "handle_segv",
112 "If set, registers the tool's custom SEGV handler (both SIGBUS and "
114 ParseFlag(str
, &f
->allow_user_segv_handler
, "allow_user_segv_handler",
115 "If set, allows user to register a SEGV handler even if the tool "
117 ParseFlag(str
, &f
->use_sigaltstack
, "use_sigaltstack",
118 "If set, uses alternate stack for signal handling.");
119 ParseFlag(str
, &f
->detect_deadlocks
, "detect_deadlocks",
120 "If set, deadlock detection is enabled.");
121 ParseFlag(str
, &f
->clear_shadow_mmap_threshold
,
122 "clear_shadow_mmap_threshold",
123 "Large shadow regions are zero-filled using mmap(NORESERVE) instead of "
124 "memset(). This is the threshold size in bytes.");
125 ParseFlag(str
, &f
->color
, "color",
126 "Colorize reports: (always|never|auto).");
127 ParseFlag(str
, &f
->legacy_pthread_cond
, "legacy_pthread_cond",
128 "Enables support for dynamic libraries linked with libpthread 2.2.5.");
129 ParseFlag(str
, &f
->intercept_tls_get_addr
, "intercept_tls_get_addr",
130 "Intercept __tls_get_addr.");
131 ParseFlag(str
, &f
->help
, "help", "Print the flag descriptions.");
132 ParseFlag(str
, &f
->mmap_limit_mb
, "mmap_limit_mb",
133 "Limit the amount of mmap-ed memory (excluding shadow) in Mb; "
134 "not a user-facing flag, used mosly for testing the tools");
135 ParseFlag(str
, &f
->coverage
, "coverage",
136 "If set, coverage information will be dumped at program shutdown (if the "
137 "coverage instrumentation was enabled at compile time).");
138 ParseFlag(str
, &f
->coverage_direct
, "coverage_direct",
139 "If set, coverage information will be dumped directly to a memory "
140 "mapped file. This way data is not lost even if the process is "
142 ParseFlag(str
, &f
->coverage_dir
, "coverage_dir",
143 "Target directory for coverage dumps. Defaults to the current "
145 ParseFlag(str
, &f
->full_address_space
, "full_address_space",
146 "Sanitize complete address space; "
147 "by default kernel area on 32-bit platforms will not be sanitized");
148 ParseFlag(str
, &f
->suppressions
, "suppressions", "Suppressions file name.");
149 ParseFlag(str
, &f
->print_suppressions
, "print_suppressions",
150 "Print matched suppressions at exit.");
151 ParseFlag(str
, &f
->disable_coredump
, "disable_coredump",
152 "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
153 "dumping a 16T+ core file. Ignored on OSes that don't dump core by"
154 "default and for sanitizers that don't reserve lots of virtual memory.");
156 // Do a sanity check for certain flags.
157 if (f
->malloc_context_size
< 1)
158 f
->malloc_context_size
= 1;
161 static bool GetFlagValue(const char *env
, const char *name
,
162 const char **value
, int *value_length
) {
167 pos
= internal_strstr(env
, name
);
170 const char *name_end
= pos
+ internal_strlen(name
);
172 ((pos
[-1] >= 'a' && pos
[-1] <= 'z') || pos
[-1] == '_')) ||
174 // Seems to be middle of another flag name or value.
188 end
= internal_strchr(pos
, '"');
189 } else if (pos
[0] == '\'') {
191 end
= internal_strchr(pos
, '\'');
193 // Read until the next space or colon.
194 end
= pos
+ internal_strcspn(pos
, " :");
197 end
= pos
+ internal_strlen(pos
);
200 *value_length
= end
- pos
;
204 static bool StartsWith(const char *flag
, int flag_length
, const char *value
) {
207 int value_length
= internal_strlen(value
);
208 return (flag_length
>= value_length
) &&
209 (0 == internal_strncmp(flag
, value
, value_length
));
212 static LowLevelAllocator allocator_for_flags
;
214 // The linear scan is suboptimal, but the number of flags is relatively small.
215 bool FlagInDescriptionList(const char *name
) {
216 IntrusiveList
<FlagDescription
>::Iterator
it(&flag_descriptions
);
217 while (it
.hasNext()) {
218 if (!internal_strcmp(it
.next()->name
, name
)) return true;
223 void AddFlagDescription(const char *name
, const char *description
) {
224 if (FlagInDescriptionList(name
)) return;
225 FlagDescription
*new_description
= new(allocator_for_flags
) FlagDescription
;
226 new_description
->name
= name
;
227 new_description
->description
= description
;
228 flag_descriptions
.push_back(new_description
);
231 // TODO(glider): put the descriptions inside CommonFlags.
232 void PrintFlagDescriptions() {
233 IntrusiveList
<FlagDescription
>::Iterator
it(&flag_descriptions
);
234 Printf("Available flags for %s:\n", SanitizerToolName
);
235 while (it
.hasNext()) {
236 FlagDescription
*descr
= it
.next();
237 Printf("\t%s\n\t\t- %s\n", descr
->name
, descr
->description
);
241 void ParseFlag(const char *env
, bool *flag
,
242 const char *name
, const char *descr
) {
245 AddFlagDescription(name
, descr
);
246 if (!GetFlagValue(env
, name
, &value
, &value_length
))
248 if (StartsWith(value
, value_length
, "0") ||
249 StartsWith(value
, value_length
, "no") ||
250 StartsWith(value
, value_length
, "false"))
252 if (StartsWith(value
, value_length
, "1") ||
253 StartsWith(value
, value_length
, "yes") ||
254 StartsWith(value
, value_length
, "true"))
258 void ParseFlag(const char *env
, int *flag
,
259 const char *name
, const char *descr
) {
262 AddFlagDescription(name
, descr
);
263 if (!GetFlagValue(env
, name
, &value
, &value_length
))
265 *flag
= static_cast<int>(internal_atoll(value
));
268 void ParseFlag(const char *env
, uptr
*flag
,
269 const char *name
, const char *descr
) {
272 AddFlagDescription(name
, descr
);
273 if (!GetFlagValue(env
, name
, &value
, &value_length
))
275 *flag
= static_cast<uptr
>(internal_atoll(value
));
278 void ParseFlag(const char *env
, const char **flag
,
279 const char *name
, const char *descr
) {
282 AddFlagDescription(name
, descr
);
283 if (!GetFlagValue(env
, name
, &value
, &value_length
))
285 // Copy the flag value. Don't use locks here, as flags are parsed at
287 char *value_copy
= (char*)(allocator_for_flags
.Allocate(value_length
+ 1));
288 internal_memcpy(value_copy
, value
, value_length
);
289 value_copy
[value_length
] = '\0';
293 } // namespace __sanitizer