sanitizer_flags.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. //===-- sanitizer_flags.cc ------------------------------------------------===//
  2. //
  3. // This file is distributed under the University of Illinois Open Source
  4. // License. See LICENSE.TXT for details.
  5. //
  6. //===----------------------------------------------------------------------===//
  7. //
  8. // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
  9. //
  10. //===----------------------------------------------------------------------===//
  11. #include "sanitizer_flags.h"
  12. #include "sanitizer_common.h"
  13. #include "sanitizer_libc.h"
  14. #include "sanitizer_list.h"
  15. namespace __sanitizer {
  16. CommonFlags common_flags_dont_use;
  17. struct FlagDescription {
  18. const char *name;
  19. const char *description;
  20. FlagDescription *next;
  21. };
  22. IntrusiveList<FlagDescription> flag_descriptions;
  23. // If set, the tool will install its own SEGV signal handler by default.
  24. #ifndef SANITIZER_NEEDS_SEGV
  25. # define SANITIZER_NEEDS_SEGV 1
  26. #endif
  27. void SetCommonFlagsDefaults(CommonFlags *f) {
  28. f->symbolize = true;
  29. f->external_symbolizer_path = 0;
  30. f->allow_addr2line = false;
  31. f->strip_path_prefix = "";
  32. f->fast_unwind_on_check = false;
  33. f->fast_unwind_on_fatal = false;
  34. f->fast_unwind_on_malloc = true;
  35. f->handle_ioctl = false;
  36. f->malloc_context_size = 1;
  37. f->log_path = "stderr";
  38. f->verbosity = 0;
  39. f->detect_leaks = true;
  40. f->leak_check_at_exit = true;
  41. f->allocator_may_return_null = false;
  42. f->print_summary = true;
  43. f->check_printf = true;
  44. // TODO(glider): tools may want to set different defaults for handle_segv.
  45. f->handle_segv = SANITIZER_NEEDS_SEGV;
  46. f->allow_user_segv_handler = false;
  47. f->use_sigaltstack = true;
  48. f->detect_deadlocks = false;
  49. f->clear_shadow_mmap_threshold = 64 * 1024;
  50. f->color = "auto";
  51. f->legacy_pthread_cond = false;
  52. f->intercept_tls_get_addr = false;
  53. f->coverage = false;
  54. f->coverage_direct = SANITIZER_ANDROID;
  55. f->coverage_dir = ".";
  56. f->full_address_space = false;
  57. f->suppressions = "";
  58. f->print_suppressions = true;
  59. f->disable_coredump = (SANITIZER_WORDSIZE == 64);
  60. f->symbolize_inline_frames = true;
  61. f->stack_trace_format = "DEFAULT";
  62. }
  63. void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
  64. ParseFlag(str, &f->symbolize, "symbolize",
  65. "If set, use the online symbolizer from common sanitizer runtime to turn "
  66. "virtual addresses to file/line locations.");
  67. ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path",
  68. "Path to external symbolizer. If empty, the tool will search $PATH for "
  69. "the symbolizer.");
  70. ParseFlag(str, &f->allow_addr2line, "allow_addr2line",
  71. "If set, allows online symbolizer to run addr2line binary to symbolize "
  72. "stack traces (addr2line will only be used if llvm-symbolizer binary is "
  73. "unavailable.");
  74. ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix",
  75. "Strips this prefix from file paths in error reports.");
  76. ParseFlag(str, &f->fast_unwind_on_check, "fast_unwind_on_check",
  77. "If available, use the fast frame-pointer-based unwinder on "
  78. "internal CHECK failures.");
  79. ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal",
  80. "If available, use the fast frame-pointer-based unwinder on fatal "
  81. "errors.");
  82. ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc",
  83. "If available, use the fast frame-pointer-based unwinder on "
  84. "malloc/free.");
  85. ParseFlag(str, &f->handle_ioctl, "handle_ioctl",
  86. "Intercept and handle ioctl requests.");
  87. ParseFlag(str, &f->malloc_context_size, "malloc_context_size",
  88. "Max number of stack frames kept for each allocation/deallocation.");
  89. ParseFlag(str, &f->log_path, "log_path",
  90. "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
  91. "\"stderr\". The default is \"stderr\".");
  92. ParseFlag(str, &f->verbosity, "verbosity",
  93. "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).");
  94. ParseFlag(str, &f->detect_leaks, "detect_leaks",
  95. "Enable memory leak detection.");
  96. ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit",
  97. "Invoke leak checking in an atexit handler. Has no effect if "
  98. "detect_leaks=false, or if __lsan_do_leak_check() is called before the "
  99. "handler has a chance to run.");
  100. ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null",
  101. "If false, the allocator will crash instead of returning 0 on "
  102. "out-of-memory.");
  103. ParseFlag(str, &f->print_summary, "print_summary",
  104. "If false, disable printing error summaries in addition to error "
  105. "reports.");
  106. ParseFlag(str, &f->check_printf, "check_printf",
  107. "Check printf arguments.");
  108. ParseFlag(str, &f->handle_segv, "handle_segv",
  109. "If set, registers the tool's custom SEGV handler (both SIGBUS and "
  110. "SIGSEGV on OSX).");
  111. ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler",
  112. "If set, allows user to register a SEGV handler even if the tool "
  113. "registers one.");
  114. ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack",
  115. "If set, uses alternate stack for signal handling.");
  116. ParseFlag(str, &f->detect_deadlocks, "detect_deadlocks",
  117. "If set, deadlock detection is enabled.");
  118. ParseFlag(str, &f->clear_shadow_mmap_threshold,
  119. "clear_shadow_mmap_threshold",
  120. "Large shadow regions are zero-filled using mmap(NORESERVE) instead of "
  121. "memset(). This is the threshold size in bytes.");
  122. ParseFlag(str, &f->color, "color",
  123. "Colorize reports: (always|never|auto).");
  124. ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond",
  125. "Enables support for dynamic libraries linked with libpthread 2.2.5.");
  126. ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr",
  127. "Intercept __tls_get_addr.");
  128. ParseFlag(str, &f->help, "help", "Print the flag descriptions.");
  129. ParseFlag(str, &f->mmap_limit_mb, "mmap_limit_mb",
  130. "Limit the amount of mmap-ed memory (excluding shadow) in Mb; "
  131. "not a user-facing flag, used mosly for testing the tools");
  132. ParseFlag(str, &f->coverage, "coverage",
  133. "If set, coverage information will be dumped at program shutdown (if the "
  134. "coverage instrumentation was enabled at compile time).");
  135. ParseFlag(str, &f->coverage_direct, "coverage_direct",
  136. "If set, coverage information will be dumped directly to a memory "
  137. "mapped file. This way data is not lost even if the process is "
  138. "suddenly killed.");
  139. ParseFlag(str, &f->coverage_dir, "coverage_dir",
  140. "Target directory for coverage dumps. Defaults to the current "
  141. "directory.");
  142. ParseFlag(str, &f->full_address_space, "full_address_space",
  143. "Sanitize complete address space; "
  144. "by default kernel area on 32-bit platforms will not be sanitized");
  145. ParseFlag(str, &f->suppressions, "suppressions", "Suppressions file name.");
  146. ParseFlag(str, &f->print_suppressions, "print_suppressions",
  147. "Print matched suppressions at exit.");
  148. ParseFlag(str, &f->disable_coredump, "disable_coredump",
  149. "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
  150. "dumping a 16T+ core file. Ignored on OSes that don't dump core by"
  151. "default and for sanitizers that don't reserve lots of virtual memory.");
  152. ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames",
  153. "Print inlined frames in stacktraces. Defaults to true.");
  154. ParseFlag(str, &f->stack_trace_format, "stack_trace_format",
  155. "Format string used to render stack frames. "
  156. "See sanitizer_stacktrace_printer.h for the format description. "
  157. "Use DEFAULT to get default format.");
  158. // Do a sanity check for certain flags.
  159. if (f->malloc_context_size < 1)
  160. f->malloc_context_size = 1;
  161. }
  162. static bool GetFlagValue(const char *env, const char *name,
  163. const char **value, int *value_length) {
  164. if (env == 0)
  165. return false;
  166. const char *pos = 0;
  167. for (;;) {
  168. pos = internal_strstr(env, name);
  169. if (pos == 0)
  170. return false;
  171. const char *name_end = pos + internal_strlen(name);
  172. if ((pos != env &&
  173. ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) ||
  174. *name_end != '=') {
  175. // Seems to be middle of another flag name or value.
  176. env = pos + 1;
  177. continue;
  178. }
  179. pos = name_end;
  180. break;
  181. }
  182. const char *end;
  183. if (pos[0] != '=') {
  184. end = pos;
  185. } else {
  186. pos += 1;
  187. if (pos[0] == '"') {
  188. pos += 1;
  189. end = internal_strchr(pos, '"');
  190. } else if (pos[0] == '\'') {
  191. pos += 1;
  192. end = internal_strchr(pos, '\'');
  193. } else {
  194. // Read until the next space or colon.
  195. end = pos + internal_strcspn(pos, " :");
  196. }
  197. if (end == 0)
  198. end = pos + internal_strlen(pos);
  199. }
  200. *value = pos;
  201. *value_length = end - pos;
  202. return true;
  203. }
  204. static bool StartsWith(const char *flag, int flag_length, const char *value) {
  205. if (!flag || !value)
  206. return false;
  207. int value_length = internal_strlen(value);
  208. return (flag_length >= value_length) &&
  209. (0 == internal_strncmp(flag, value, value_length));
  210. }
  211. static LowLevelAllocator allocator_for_flags;
  212. // The linear scan is suboptimal, but the number of flags is relatively small.
  213. bool FlagInDescriptionList(const char *name) {
  214. IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
  215. while (it.hasNext()) {
  216. if (!internal_strcmp(it.next()->name, name)) return true;
  217. }
  218. return false;
  219. }
  220. void AddFlagDescription(const char *name, const char *description) {
  221. if (FlagInDescriptionList(name)) return;
  222. FlagDescription *new_description = new(allocator_for_flags) FlagDescription;
  223. new_description->name = name;
  224. new_description->description = description;
  225. flag_descriptions.push_back(new_description);
  226. }
  227. // TODO(glider): put the descriptions inside CommonFlags.
  228. void PrintFlagDescriptions() {
  229. IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
  230. Printf("Available flags for %s:\n", SanitizerToolName);
  231. while (it.hasNext()) {
  232. FlagDescription *descr = it.next();
  233. Printf("\t%s\n\t\t- %s\n", descr->name, descr->description);
  234. }
  235. }
  236. void ParseFlag(const char *env, bool *flag,
  237. const char *name, const char *descr) {
  238. const char *value;
  239. int value_length;
  240. AddFlagDescription(name, descr);
  241. if (!GetFlagValue(env, name, &value, &value_length))
  242. return;
  243. if (StartsWith(value, value_length, "0") ||
  244. StartsWith(value, value_length, "no") ||
  245. StartsWith(value, value_length, "false"))
  246. *flag = false;
  247. if (StartsWith(value, value_length, "1") ||
  248. StartsWith(value, value_length, "yes") ||
  249. StartsWith(value, value_length, "true"))
  250. *flag = true;
  251. }
  252. void ParseFlag(const char *env, int *flag,
  253. const char *name, const char *descr) {
  254. const char *value;
  255. int value_length;
  256. AddFlagDescription(name, descr);
  257. if (!GetFlagValue(env, name, &value, &value_length))
  258. return;
  259. *flag = static_cast<int>(internal_atoll(value));
  260. }
  261. void ParseFlag(const char *env, uptr *flag,
  262. const char *name, const char *descr) {
  263. const char *value;
  264. int value_length;
  265. AddFlagDescription(name, descr);
  266. if (!GetFlagValue(env, name, &value, &value_length))
  267. return;
  268. *flag = static_cast<uptr>(internal_atoll(value));
  269. }
  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. } // namespace __sanitizer