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 void SetCommonFlagsDefaults(CommonFlags
*f
) {
32 f
->external_symbolizer_path
= 0;
33 f
->allow_addr2line
= false;
34 f
->strip_path_prefix
= "";
35 f
->fast_unwind_on_fatal
= false;
36 f
->fast_unwind_on_malloc
= true;
37 f
->handle_ioctl
= false;
38 f
->malloc_context_size
= 1;
39 f
->log_path
= "stderr";
41 f
->detect_leaks
= true;
42 f
->leak_check_at_exit
= true;
43 f
->allocator_may_return_null
= false;
44 f
->print_summary
= true;
45 f
->check_printf
= true;
46 // TODO(glider): tools may want to set different defaults for handle_segv.
47 f
->handle_segv
= SANITIZER_NEEDS_SEGV
;
48 f
->allow_user_segv_handler
= false;
49 f
->use_sigaltstack
= true;
50 f
->detect_deadlocks
= false;
51 f
->clear_shadow_mmap_threshold
= 64 * 1024;
53 f
->legacy_pthread_cond
= false;
54 f
->intercept_tls_get_addr
= false;
56 f
->full_address_space
= false;
59 void ParseCommonFlagsFromString(CommonFlags
*f
, const char *str
) {
60 ParseFlag(str
, &f
->symbolize
, "symbolize",
61 "If set, use the online symbolizer from common sanitizer runtime to turn "
62 "virtual addresses to file/line locations.");
63 ParseFlag(str
, &f
->external_symbolizer_path
, "external_symbolizer_path",
64 "Path to external symbolizer. If empty, the tool will search $PATH for "
66 ParseFlag(str
, &f
->allow_addr2line
, "allow_addr2line",
67 "If set, allows online symbolizer to run addr2line binary to symbolize "
68 "stack traces (addr2line will only be used if llvm-symbolizer binary is "
70 ParseFlag(str
, &f
->strip_path_prefix
, "strip_path_prefix",
71 "Strips this prefix from file paths in error reports.");
72 ParseFlag(str
, &f
->fast_unwind_on_fatal
, "fast_unwind_on_fatal",
73 "If available, use the fast frame-pointer-based unwinder on fatal "
75 ParseFlag(str
, &f
->fast_unwind_on_malloc
, "fast_unwind_on_malloc",
76 "If available, use the fast frame-pointer-based unwinder on "
78 ParseFlag(str
, &f
->handle_ioctl
, "handle_ioctl",
79 "Intercept and handle ioctl requests.");
80 ParseFlag(str
, &f
->malloc_context_size
, "malloc_context_size",
81 "Max number of stack frames kept for each allocation/deallocation.");
82 ParseFlag(str
, &f
->log_path
, "log_path",
83 "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
84 "\"stderr\". The default is \"stderr\".");
85 ParseFlag(str
, &f
->verbosity
, "verbosity",
86 "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).");
87 ParseFlag(str
, &f
->detect_leaks
, "detect_leaks",
88 "Enable memory leak detection.");
89 ParseFlag(str
, &f
->leak_check_at_exit
, "leak_check_at_exit",
90 "Invoke leak checking in an atexit handler. Has no effect if "
91 "detect_leaks=false, or if __lsan_do_leak_check() is called before the "
92 "handler has a chance to run.");
93 ParseFlag(str
, &f
->allocator_may_return_null
, "allocator_may_return_null",
94 "If false, the allocator will crash instead of returning 0 on "
96 ParseFlag(str
, &f
->print_summary
, "print_summary",
97 "If false, disable printing error summaries in addition to error "
99 ParseFlag(str
, &f
->check_printf
, "check_printf",
100 "Check printf arguments.");
101 ParseFlag(str
, &f
->handle_segv
, "handle_segv",
102 "If set, registers the tool's custom SEGV handler (both SIGBUS and "
104 ParseFlag(str
, &f
->allow_user_segv_handler
, "allow_user_segv_handler",
105 "If set, allows user to register a SEGV handler even if the tool "
107 ParseFlag(str
, &f
->use_sigaltstack
, "use_sigaltstack",
108 "If set, uses alternate stack for signal handling.");
109 ParseFlag(str
, &f
->detect_deadlocks
, "detect_deadlocks",
110 "If set, deadlock detection is enabled.");
111 ParseFlag(str
, &f
->clear_shadow_mmap_threshold
,
112 "clear_shadow_mmap_threshold",
113 "Large shadow regions are zero-filled using mmap(NORESERVE) instead of "
114 "memset(). This is the threshold size in bytes.");
115 ParseFlag(str
, &f
->color
, "color",
116 "Colorize reports: (always|never|auto).");
117 ParseFlag(str
, &f
->legacy_pthread_cond
, "legacy_pthread_cond",
118 "Enables support for dynamic libraries linked with libpthread 2.2.5.");
119 ParseFlag(str
, &f
->intercept_tls_get_addr
, "intercept_tls_get_addr",
120 "Intercept __tls_get_addr.");
121 ParseFlag(str
, &f
->help
, "help", "Print the flag descriptions.");
122 ParseFlag(str
, &f
->mmap_limit_mb
, "mmap_limit_mb",
123 "Limit the amount of mmap-ed memory (excluding shadow) in Mb; "
124 "not a user-facing flag, used mosly for testing the tools");
125 ParseFlag(str
, &f
->coverage
, "coverage",
126 "If set, coverage information will be dumped at program shutdown (if the "
127 "coverage instrumentation was enabled at compile time).");
128 ParseFlag(str
, &f
->full_address_space
, "full_address_space",
129 "Sanitize complete address space; "
130 "by default kernel area on 32-bit platforms will not be sanitized");
132 // Do a sanity check for certain flags.
133 if (f
->malloc_context_size
< 1)
134 f
->malloc_context_size
= 1;
137 static bool GetFlagValue(const char *env
, const char *name
,
138 const char **value
, int *value_length
) {
143 pos
= internal_strstr(env
, name
);
146 if (pos
!= env
&& ((pos
[-1] >= 'a' && pos
[-1] <= 'z') || pos
[-1] == '_')) {
147 // Seems to be middle of another flag name or value.
153 pos
+= internal_strlen(name
);
161 end
= internal_strchr(pos
, '"');
162 } else if (pos
[0] == '\'') {
164 end
= internal_strchr(pos
, '\'');
166 // Read until the next space or colon.
167 end
= pos
+ internal_strcspn(pos
, " :");
170 end
= pos
+ internal_strlen(pos
);
173 *value_length
= end
- pos
;
177 static bool StartsWith(const char *flag
, int flag_length
, const char *value
) {
180 int value_length
= internal_strlen(value
);
181 return (flag_length
>= value_length
) &&
182 (0 == internal_strncmp(flag
, value
, value_length
));
185 static LowLevelAllocator allocator_for_flags
;
187 // The linear scan is suboptimal, but the number of flags is relatively small.
188 bool FlagInDescriptionList(const char *name
) {
189 IntrusiveList
<FlagDescription
>::Iterator
it(&flag_descriptions
);
190 while (it
.hasNext()) {
191 if (!internal_strcmp(it
.next()->name
, name
)) return true;
196 void AddFlagDescription(const char *name
, const char *description
) {
197 if (FlagInDescriptionList(name
)) return;
198 FlagDescription
*new_description
= new(allocator_for_flags
) FlagDescription
;
199 new_description
->name
= name
;
200 new_description
->description
= description
;
201 flag_descriptions
.push_back(new_description
);
204 // TODO(glider): put the descriptions inside CommonFlags.
205 void PrintFlagDescriptions() {
206 IntrusiveList
<FlagDescription
>::Iterator
it(&flag_descriptions
);
207 Printf("Available flags for %s:\n", SanitizerToolName
);
208 while (it
.hasNext()) {
209 FlagDescription
*descr
= it
.next();
210 Printf("\t%s\n\t\t- %s\n", descr
->name
, descr
->description
);
214 void ParseFlag(const char *env
, bool *flag
,
215 const char *name
, const char *descr
) {
218 AddFlagDescription(name
, descr
);
219 if (!GetFlagValue(env
, name
, &value
, &value_length
))
221 if (StartsWith(value
, value_length
, "0") ||
222 StartsWith(value
, value_length
, "no") ||
223 StartsWith(value
, value_length
, "false"))
225 if (StartsWith(value
, value_length
, "1") ||
226 StartsWith(value
, value_length
, "yes") ||
227 StartsWith(value
, value_length
, "true"))
231 void ParseFlag(const char *env
, int *flag
,
232 const char *name
, const char *descr
) {
235 AddFlagDescription(name
, descr
);
236 if (!GetFlagValue(env
, name
, &value
, &value_length
))
238 *flag
= static_cast<int>(internal_atoll(value
));
241 void ParseFlag(const char *env
, uptr
*flag
,
242 const char *name
, const char *descr
) {
245 AddFlagDescription(name
, descr
);
246 if (!GetFlagValue(env
, name
, &value
, &value_length
))
248 *flag
= static_cast<uptr
>(internal_atoll(value
));
251 void ParseFlag(const char *env
, const char **flag
,
252 const char *name
, const char *descr
) {
255 AddFlagDescription(name
, descr
);
256 if (!GetFlagValue(env
, name
, &value
, &value_length
))
258 // Copy the flag value. Don't use locks here, as flags are parsed at
260 char *value_copy
= (char*)(allocator_for_flags
.Allocate(value_length
+ 1));
261 internal_memcpy(value_copy
, value
, value_length
);
262 value_copy
[value_length
] = '\0';
266 } // namespace __sanitizer