1//===-- tsan_flags.cpp ----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of ThreadSanitizer (TSan), a race detector.
10//
11//===----------------------------------------------------------------------===//
12
13#include "tsan_flags.h"
14
15#include "sanitizer_common/sanitizer_flag_parser.h"
16#include "sanitizer_common/sanitizer_flags.h"
17#include "sanitizer_common/sanitizer_libc.h"
18#include "tsan_interface.h"
19#include "tsan_mman.h"
20#include "tsan_rtl.h"
21#include "ubsan/ubsan_flags.h"
22
23#if SANITIZER_APPLE && !SANITIZER_GO
24namespace __sanitizer {
25
26template <>
27inline bool FlagHandler<LockDuringWriteSetting>::Parse(const char *value) {
28 if (internal_strcmp(value, "on") == 0) {
29 *t_ = kLockDuringAllWrites;
30 return true;
31 }
32 if (internal_strcmp(value, "disable_for_current_process") == 0) {
33 *t_ = kNoLockDuringWritesCurrentProcess;
34 return true;
35 }
36 if (internal_strcmp(value, "disable_for_all_processes") == 0) {
37 *t_ = kNoLockDuringWritesAllProcesses;
38 return true;
39 }
40 Printf("ERROR: Invalid value for lock_during_write option: '%s'\n", value);
41 return false;
42}
43
44template <>
45inline bool FlagHandler<LockDuringWriteSetting>::Format(char *buffer,
46 uptr size) {
47 switch (*t_) {
48 case kLockDuringAllWrites:
49 return FormatString(buffer, size, "on");
50 case kNoLockDuringWritesCurrentProcess:
51 return FormatString(buffer, size, "disable_for_current_process");
52 case kNoLockDuringWritesAllProcesses:
53 return FormatString(buffer, size, "disable_for_all_processes");
54 }
55}
56
57} // namespace __sanitizer
58#endif // SANITIZER_APPLE && !SANITIZER_GO
59
60namespace __tsan {
61
62// Can be overriden in frontend.
63#ifdef TSAN_EXTERNAL_HOOKS
64extern "C" const char *__tsan_default_options();
65#else
66SANITIZER_WEAK_DEFAULT_IMPL
67const char *__tsan_default_options() {
68 return "";
69}
70#endif
71
72void Flags::SetDefaults() {
73#define TSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
74#include "tsan_flags.inc"
75#undef TSAN_FLAG
76 // DDFlags
77 second_deadlock_stack = false;
78}
79
80void RegisterTsanFlags(FlagParser *parser, Flags *f) {
81#define TSAN_FLAG(Type, Name, DefaultValue, Description) \
82 RegisterFlag(parser, #Name, Description, &f->Name);
83#include "tsan_flags.inc"
84#undef TSAN_FLAG
85 // DDFlags
86 RegisterFlag(parser, name: "second_deadlock_stack",
87 desc: "Report where each mutex is locked in deadlock reports",
88 var: &f->second_deadlock_stack);
89}
90
91void InitializeFlags(Flags *f, const char *env, const char *env_option_name) {
92 SetCommonFlagsDefaults();
93 {
94 // Override some common flags defaults.
95 CommonFlags cf;
96 cf.CopyFrom(other: *common_flags());
97 cf.external_symbolizer_path = GetEnv(name: "TSAN_SYMBOLIZER_PATH");
98 cf.allow_addr2line = true;
99 if (SANITIZER_GO) {
100 // Does not work as expected for Go: runtime handles SIGABRT and crashes.
101 cf.abort_on_error = false;
102 // Go does not have mutexes.
103 cf.detect_deadlocks = false;
104 }
105 cf.print_suppressions = false;
106 cf.stack_trace_format = " #%n %f %S %M";
107 cf.exitcode = 66;
108 cf.intercept_tls_get_addr = true;
109 OverrideCommonFlags(cf);
110 }
111
112 f->SetDefaults();
113
114 FlagParser parser;
115 RegisterTsanFlags(parser: &parser, f);
116 RegisterCommonFlags(parser: &parser);
117
118#if TSAN_CONTAINS_UBSAN
119 __ubsan::Flags *uf = __ubsan::flags();
120 uf->SetDefaults();
121
122 FlagParser ubsan_parser;
123 __ubsan::RegisterUbsanFlags(parser: &ubsan_parser, f: uf);
124 RegisterCommonFlags(parser: &ubsan_parser);
125#endif
126
127 // Let a frontend override.
128 parser.ParseString(s: __tsan_default_options());
129#if TSAN_CONTAINS_UBSAN
130 const char *ubsan_default_options = __ubsan_default_options();
131 ubsan_parser.ParseString(s: ubsan_default_options);
132#endif
133 // Override from command line.
134 parser.ParseString(s: env, env_name: env_option_name);
135#if TSAN_CONTAINS_UBSAN
136 ubsan_parser.ParseStringFromEnv(env_name: "UBSAN_OPTIONS");
137#endif
138
139 // Check flags.
140 if (!f->report_bugs) {
141 f->report_thread_leaks = false;
142 f->report_destroy_locked = false;
143 f->report_signal_unsafe = false;
144 }
145
146 InitializeCommonFlags();
147
148 if (Verbosity()) ReportUnrecognizedFlags();
149
150 if (common_flags()->help) parser.PrintFlagDescriptions();
151
152 if (f->io_sync < 0 || f->io_sync > 2) {
153 Printf(format: "ThreadSanitizer: incorrect value for io_sync"
154 " (must be [0..2])\n");
155 Die();
156 }
157}
158
159} // namespace __tsan
160