annotate libsanitizer/tsan/tsan_rtl.h @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 //===-- tsan_rtl.h ----------------------------------------------*- C++ -*-===//
kono
parents:
diff changeset
2 //
kono
parents:
diff changeset
3 // This file is distributed under the University of Illinois Open Source
kono
parents:
diff changeset
4 // License. See LICENSE.TXT for details.
kono
parents:
diff changeset
5 //
kono
parents:
diff changeset
6 //===----------------------------------------------------------------------===//
kono
parents:
diff changeset
7 //
kono
parents:
diff changeset
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
kono
parents:
diff changeset
9 //
kono
parents:
diff changeset
10 // Main internal TSan header file.
kono
parents:
diff changeset
11 //
kono
parents:
diff changeset
12 // Ground rules:
kono
parents:
diff changeset
13 // - C++ run-time should not be used (static CTORs, RTTI, exceptions, static
kono
parents:
diff changeset
14 // function-scope locals)
kono
parents:
diff changeset
15 // - All functions/classes/etc reside in namespace __tsan, except for those
kono
parents:
diff changeset
16 // declared in tsan_interface.h.
kono
parents:
diff changeset
17 // - Platform-specific files should be used instead of ifdefs (*).
kono
parents:
diff changeset
18 // - No system headers included in header files (*).
kono
parents:
diff changeset
19 // - Platform specific headres included only into platform-specific files (*).
kono
parents:
diff changeset
20 //
kono
parents:
diff changeset
21 // (*) Except when inlining is critical for performance.
kono
parents:
diff changeset
22 //===----------------------------------------------------------------------===//
kono
parents:
diff changeset
23
kono
parents:
diff changeset
24 #ifndef TSAN_RTL_H
kono
parents:
diff changeset
25 #define TSAN_RTL_H
kono
parents:
diff changeset
26
kono
parents:
diff changeset
27 #include "sanitizer_common/sanitizer_allocator.h"
kono
parents:
diff changeset
28 #include "sanitizer_common/sanitizer_allocator_internal.h"
kono
parents:
diff changeset
29 #include "sanitizer_common/sanitizer_asm.h"
kono
parents:
diff changeset
30 #include "sanitizer_common/sanitizer_common.h"
kono
parents:
diff changeset
31 #include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
kono
parents:
diff changeset
32 #include "sanitizer_common/sanitizer_libignore.h"
kono
parents:
diff changeset
33 #include "sanitizer_common/sanitizer_suppressions.h"
kono
parents:
diff changeset
34 #include "sanitizer_common/sanitizer_thread_registry.h"
kono
parents:
diff changeset
35 #include "tsan_clock.h"
kono
parents:
diff changeset
36 #include "tsan_defs.h"
kono
parents:
diff changeset
37 #include "tsan_flags.h"
kono
parents:
diff changeset
38 #include "tsan_sync.h"
kono
parents:
diff changeset
39 #include "tsan_trace.h"
kono
parents:
diff changeset
40 #include "tsan_vector.h"
kono
parents:
diff changeset
41 #include "tsan_report.h"
kono
parents:
diff changeset
42 #include "tsan_platform.h"
kono
parents:
diff changeset
43 #include "tsan_mutexset.h"
kono
parents:
diff changeset
44 #include "tsan_ignoreset.h"
kono
parents:
diff changeset
45 #include "tsan_stack_trace.h"
kono
parents:
diff changeset
46
kono
parents:
diff changeset
47 #if SANITIZER_WORDSIZE != 64
kono
parents:
diff changeset
48 # error "ThreadSanitizer is supported only on 64-bit platforms"
kono
parents:
diff changeset
49 #endif
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51 namespace __tsan {
kono
parents:
diff changeset
52
kono
parents:
diff changeset
53 #if !SANITIZER_GO
kono
parents:
diff changeset
54 struct MapUnmapCallback;
kono
parents:
diff changeset
55 #if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__)
kono
parents:
diff changeset
56 static const uptr kAllocatorRegionSizeLog = 20;
kono
parents:
diff changeset
57 static const uptr kAllocatorNumRegions =
kono
parents:
diff changeset
58 SANITIZER_MMAP_RANGE_SIZE >> kAllocatorRegionSizeLog;
kono
parents:
diff changeset
59 typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12,
kono
parents:
diff changeset
60 MapUnmapCallback> ByteMap;
kono
parents:
diff changeset
61 struct AP32 {
kono
parents:
diff changeset
62 static const uptr kSpaceBeg = 0;
kono
parents:
diff changeset
63 static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
kono
parents:
diff changeset
64 static const uptr kMetadataSize = 0;
kono
parents:
diff changeset
65 typedef __sanitizer::CompactSizeClassMap SizeClassMap;
kono
parents:
diff changeset
66 static const uptr kRegionSizeLog = kAllocatorRegionSizeLog;
kono
parents:
diff changeset
67 typedef __tsan::ByteMap ByteMap;
kono
parents:
diff changeset
68 typedef __tsan::MapUnmapCallback MapUnmapCallback;
kono
parents:
diff changeset
69 static const uptr kFlags = 0;
kono
parents:
diff changeset
70 };
kono
parents:
diff changeset
71 typedef SizeClassAllocator32<AP32> PrimaryAllocator;
kono
parents:
diff changeset
72 #else
kono
parents:
diff changeset
73 struct AP64 { // Allocator64 parameters. Deliberately using a short name.
kono
parents:
diff changeset
74 static const uptr kSpaceBeg = Mapping::kHeapMemBeg;
kono
parents:
diff changeset
75 static const uptr kSpaceSize = Mapping::kHeapMemEnd - Mapping::kHeapMemBeg;
kono
parents:
diff changeset
76 static const uptr kMetadataSize = 0;
kono
parents:
diff changeset
77 typedef DefaultSizeClassMap SizeClassMap;
kono
parents:
diff changeset
78 typedef __tsan::MapUnmapCallback MapUnmapCallback;
kono
parents:
diff changeset
79 static const uptr kFlags = 0;
kono
parents:
diff changeset
80 };
kono
parents:
diff changeset
81 typedef SizeClassAllocator64<AP64> PrimaryAllocator;
kono
parents:
diff changeset
82 #endif
kono
parents:
diff changeset
83 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
kono
parents:
diff changeset
84 typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator;
kono
parents:
diff changeset
85 typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
kono
parents:
diff changeset
86 SecondaryAllocator> Allocator;
kono
parents:
diff changeset
87 Allocator *allocator();
kono
parents:
diff changeset
88 #endif
kono
parents:
diff changeset
89
kono
parents:
diff changeset
90 void TsanCheckFailed(const char *file, int line, const char *cond,
kono
parents:
diff changeset
91 u64 v1, u64 v2);
kono
parents:
diff changeset
92
kono
parents:
diff changeset
93 const u64 kShadowRodata = (u64)-1; // .rodata shadow marker
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 // FastState (from most significant bit):
kono
parents:
diff changeset
96 // ignore : 1
kono
parents:
diff changeset
97 // tid : kTidBits
kono
parents:
diff changeset
98 // unused : -
kono
parents:
diff changeset
99 // history_size : 3
kono
parents:
diff changeset
100 // epoch : kClkBits
kono
parents:
diff changeset
101 class FastState {
kono
parents:
diff changeset
102 public:
kono
parents:
diff changeset
103 FastState(u64 tid, u64 epoch) {
kono
parents:
diff changeset
104 x_ = tid << kTidShift;
kono
parents:
diff changeset
105 x_ |= epoch;
kono
parents:
diff changeset
106 DCHECK_EQ(tid, this->tid());
kono
parents:
diff changeset
107 DCHECK_EQ(epoch, this->epoch());
kono
parents:
diff changeset
108 DCHECK_EQ(GetIgnoreBit(), false);
kono
parents:
diff changeset
109 }
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 explicit FastState(u64 x)
kono
parents:
diff changeset
112 : x_(x) {
kono
parents:
diff changeset
113 }
kono
parents:
diff changeset
114
kono
parents:
diff changeset
115 u64 raw() const {
kono
parents:
diff changeset
116 return x_;
kono
parents:
diff changeset
117 }
kono
parents:
diff changeset
118
kono
parents:
diff changeset
119 u64 tid() const {
kono
parents:
diff changeset
120 u64 res = (x_ & ~kIgnoreBit) >> kTidShift;
kono
parents:
diff changeset
121 return res;
kono
parents:
diff changeset
122 }
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 u64 TidWithIgnore() const {
kono
parents:
diff changeset
125 u64 res = x_ >> kTidShift;
kono
parents:
diff changeset
126 return res;
kono
parents:
diff changeset
127 }
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 u64 epoch() const {
kono
parents:
diff changeset
130 u64 res = x_ & ((1ull << kClkBits) - 1);
kono
parents:
diff changeset
131 return res;
kono
parents:
diff changeset
132 }
kono
parents:
diff changeset
133
kono
parents:
diff changeset
134 void IncrementEpoch() {
kono
parents:
diff changeset
135 u64 old_epoch = epoch();
kono
parents:
diff changeset
136 x_ += 1;
kono
parents:
diff changeset
137 DCHECK_EQ(old_epoch + 1, epoch());
kono
parents:
diff changeset
138 (void)old_epoch;
kono
parents:
diff changeset
139 }
kono
parents:
diff changeset
140
kono
parents:
diff changeset
141 void SetIgnoreBit() { x_ |= kIgnoreBit; }
kono
parents:
diff changeset
142 void ClearIgnoreBit() { x_ &= ~kIgnoreBit; }
kono
parents:
diff changeset
143 bool GetIgnoreBit() const { return (s64)x_ < 0; }
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 void SetHistorySize(int hs) {
kono
parents:
diff changeset
146 CHECK_GE(hs, 0);
kono
parents:
diff changeset
147 CHECK_LE(hs, 7);
kono
parents:
diff changeset
148 x_ = (x_ & ~(kHistoryMask << kHistoryShift)) | (u64(hs) << kHistoryShift);
kono
parents:
diff changeset
149 }
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 ALWAYS_INLINE
kono
parents:
diff changeset
152 int GetHistorySize() const {
kono
parents:
diff changeset
153 return (int)((x_ >> kHistoryShift) & kHistoryMask);
kono
parents:
diff changeset
154 }
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 void ClearHistorySize() {
kono
parents:
diff changeset
157 SetHistorySize(0);
kono
parents:
diff changeset
158 }
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 ALWAYS_INLINE
kono
parents:
diff changeset
161 u64 GetTracePos() const {
kono
parents:
diff changeset
162 const int hs = GetHistorySize();
kono
parents:
diff changeset
163 // When hs == 0, the trace consists of 2 parts.
kono
parents:
diff changeset
164 const u64 mask = (1ull << (kTracePartSizeBits + hs + 1)) - 1;
kono
parents:
diff changeset
165 return epoch() & mask;
kono
parents:
diff changeset
166 }
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 private:
kono
parents:
diff changeset
169 friend class Shadow;
kono
parents:
diff changeset
170 static const int kTidShift = 64 - kTidBits - 1;
kono
parents:
diff changeset
171 static const u64 kIgnoreBit = 1ull << 63;
kono
parents:
diff changeset
172 static const u64 kFreedBit = 1ull << 63;
kono
parents:
diff changeset
173 static const u64 kHistoryShift = kClkBits;
kono
parents:
diff changeset
174 static const u64 kHistoryMask = 7;
kono
parents:
diff changeset
175 u64 x_;
kono
parents:
diff changeset
176 };
kono
parents:
diff changeset
177
kono
parents:
diff changeset
178 // Shadow (from most significant bit):
kono
parents:
diff changeset
179 // freed : 1
kono
parents:
diff changeset
180 // tid : kTidBits
kono
parents:
diff changeset
181 // is_atomic : 1
kono
parents:
diff changeset
182 // is_read : 1
kono
parents:
diff changeset
183 // size_log : 2
kono
parents:
diff changeset
184 // addr0 : 3
kono
parents:
diff changeset
185 // epoch : kClkBits
kono
parents:
diff changeset
186 class Shadow : public FastState {
kono
parents:
diff changeset
187 public:
kono
parents:
diff changeset
188 explicit Shadow(u64 x)
kono
parents:
diff changeset
189 : FastState(x) {
kono
parents:
diff changeset
190 }
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 explicit Shadow(const FastState &s)
kono
parents:
diff changeset
193 : FastState(s.x_) {
kono
parents:
diff changeset
194 ClearHistorySize();
kono
parents:
diff changeset
195 }
kono
parents:
diff changeset
196
kono
parents:
diff changeset
197 void SetAddr0AndSizeLog(u64 addr0, unsigned kAccessSizeLog) {
kono
parents:
diff changeset
198 DCHECK_EQ((x_ >> kClkBits) & 31, 0);
kono
parents:
diff changeset
199 DCHECK_LE(addr0, 7);
kono
parents:
diff changeset
200 DCHECK_LE(kAccessSizeLog, 3);
kono
parents:
diff changeset
201 x_ |= ((kAccessSizeLog << 3) | addr0) << kClkBits;
kono
parents:
diff changeset
202 DCHECK_EQ(kAccessSizeLog, size_log());
kono
parents:
diff changeset
203 DCHECK_EQ(addr0, this->addr0());
kono
parents:
diff changeset
204 }
kono
parents:
diff changeset
205
kono
parents:
diff changeset
206 void SetWrite(unsigned kAccessIsWrite) {
kono
parents:
diff changeset
207 DCHECK_EQ(x_ & kReadBit, 0);
kono
parents:
diff changeset
208 if (!kAccessIsWrite)
kono
parents:
diff changeset
209 x_ |= kReadBit;
kono
parents:
diff changeset
210 DCHECK_EQ(kAccessIsWrite, IsWrite());
kono
parents:
diff changeset
211 }
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 void SetAtomic(bool kIsAtomic) {
kono
parents:
diff changeset
214 DCHECK(!IsAtomic());
kono
parents:
diff changeset
215 if (kIsAtomic)
kono
parents:
diff changeset
216 x_ |= kAtomicBit;
kono
parents:
diff changeset
217 DCHECK_EQ(IsAtomic(), kIsAtomic);
kono
parents:
diff changeset
218 }
kono
parents:
diff changeset
219
kono
parents:
diff changeset
220 bool IsAtomic() const {
kono
parents:
diff changeset
221 return x_ & kAtomicBit;
kono
parents:
diff changeset
222 }
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 bool IsZero() const {
kono
parents:
diff changeset
225 return x_ == 0;
kono
parents:
diff changeset
226 }
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) {
kono
parents:
diff changeset
229 u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift;
kono
parents:
diff changeset
230 DCHECK_EQ(shifted_xor == 0, s1.TidWithIgnore() == s2.TidWithIgnore());
kono
parents:
diff changeset
231 return shifted_xor == 0;
kono
parents:
diff changeset
232 }
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 static ALWAYS_INLINE
kono
parents:
diff changeset
235 bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) {
kono
parents:
diff changeset
236 u64 masked_xor = ((s1.x_ ^ s2.x_) >> kClkBits) & 31;
kono
parents:
diff changeset
237 return masked_xor == 0;
kono
parents:
diff changeset
238 }
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 static ALWAYS_INLINE bool TwoRangesIntersect(Shadow s1, Shadow s2,
kono
parents:
diff changeset
241 unsigned kS2AccessSize) {
kono
parents:
diff changeset
242 bool res = false;
kono
parents:
diff changeset
243 u64 diff = s1.addr0() - s2.addr0();
kono
parents:
diff changeset
244 if ((s64)diff < 0) { // s1.addr0 < s2.addr0 // NOLINT
kono
parents:
diff changeset
245 // if (s1.addr0() + size1) > s2.addr0()) return true;
kono
parents:
diff changeset
246 if (s1.size() > -diff)
kono
parents:
diff changeset
247 res = true;
kono
parents:
diff changeset
248 } else {
kono
parents:
diff changeset
249 // if (s2.addr0() + kS2AccessSize > s1.addr0()) return true;
kono
parents:
diff changeset
250 if (kS2AccessSize > diff)
kono
parents:
diff changeset
251 res = true;
kono
parents:
diff changeset
252 }
kono
parents:
diff changeset
253 DCHECK_EQ(res, TwoRangesIntersectSlow(s1, s2));
kono
parents:
diff changeset
254 DCHECK_EQ(res, TwoRangesIntersectSlow(s2, s1));
kono
parents:
diff changeset
255 return res;
kono
parents:
diff changeset
256 }
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 u64 ALWAYS_INLINE addr0() const { return (x_ >> kClkBits) & 7; }
kono
parents:
diff changeset
259 u64 ALWAYS_INLINE size() const { return 1ull << size_log(); }
kono
parents:
diff changeset
260 bool ALWAYS_INLINE IsWrite() const { return !IsRead(); }
kono
parents:
diff changeset
261 bool ALWAYS_INLINE IsRead() const { return x_ & kReadBit; }
kono
parents:
diff changeset
262
kono
parents:
diff changeset
263 // The idea behind the freed bit is as follows.
kono
parents:
diff changeset
264 // When the memory is freed (or otherwise unaccessible) we write to the shadow
kono
parents:
diff changeset
265 // values with tid/epoch related to the free and the freed bit set.
kono
parents:
diff changeset
266 // During memory accesses processing the freed bit is considered
kono
parents:
diff changeset
267 // as msb of tid. So any access races with shadow with freed bit set
kono
parents:
diff changeset
268 // (it is as if write from a thread with which we never synchronized before).
kono
parents:
diff changeset
269 // This allows us to detect accesses to freed memory w/o additional
kono
parents:
diff changeset
270 // overheads in memory access processing and at the same time restore
kono
parents:
diff changeset
271 // tid/epoch of free.
kono
parents:
diff changeset
272 void MarkAsFreed() {
kono
parents:
diff changeset
273 x_ |= kFreedBit;
kono
parents:
diff changeset
274 }
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 bool IsFreed() const {
kono
parents:
diff changeset
277 return x_ & kFreedBit;
kono
parents:
diff changeset
278 }
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 bool GetFreedAndReset() {
kono
parents:
diff changeset
281 bool res = x_ & kFreedBit;
kono
parents:
diff changeset
282 x_ &= ~kFreedBit;
kono
parents:
diff changeset
283 return res;
kono
parents:
diff changeset
284 }
kono
parents:
diff changeset
285
kono
parents:
diff changeset
286 bool ALWAYS_INLINE IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const {
kono
parents:
diff changeset
287 bool v = x_ & ((u64(kIsWrite ^ 1) << kReadShift)
kono
parents:
diff changeset
288 | (u64(kIsAtomic) << kAtomicShift));
kono
parents:
diff changeset
289 DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic));
kono
parents:
diff changeset
290 return v;
kono
parents:
diff changeset
291 }
kono
parents:
diff changeset
292
kono
parents:
diff changeset
293 bool ALWAYS_INLINE IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const {
kono
parents:
diff changeset
294 bool v = ((x_ >> kReadShift) & 3)
kono
parents:
diff changeset
295 <= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
kono
parents:
diff changeset
296 DCHECK_EQ(v, (IsAtomic() < kIsAtomic) ||
kono
parents:
diff changeset
297 (IsAtomic() == kIsAtomic && !IsWrite() <= !kIsWrite));
kono
parents:
diff changeset
298 return v;
kono
parents:
diff changeset
299 }
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 bool ALWAYS_INLINE IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const {
kono
parents:
diff changeset
302 bool v = ((x_ >> kReadShift) & 3)
kono
parents:
diff changeset
303 >= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
kono
parents:
diff changeset
304 DCHECK_EQ(v, (IsAtomic() > kIsAtomic) ||
kono
parents:
diff changeset
305 (IsAtomic() == kIsAtomic && !IsWrite() >= !kIsWrite));
kono
parents:
diff changeset
306 return v;
kono
parents:
diff changeset
307 }
kono
parents:
diff changeset
308
kono
parents:
diff changeset
309 private:
kono
parents:
diff changeset
310 static const u64 kReadShift = 5 + kClkBits;
kono
parents:
diff changeset
311 static const u64 kReadBit = 1ull << kReadShift;
kono
parents:
diff changeset
312 static const u64 kAtomicShift = 6 + kClkBits;
kono
parents:
diff changeset
313 static const u64 kAtomicBit = 1ull << kAtomicShift;
kono
parents:
diff changeset
314
kono
parents:
diff changeset
315 u64 size_log() const { return (x_ >> (3 + kClkBits)) & 3; }
kono
parents:
diff changeset
316
kono
parents:
diff changeset
317 static bool TwoRangesIntersectSlow(const Shadow s1, const Shadow s2) {
kono
parents:
diff changeset
318 if (s1.addr0() == s2.addr0()) return true;
kono
parents:
diff changeset
319 if (s1.addr0() < s2.addr0() && s1.addr0() + s1.size() > s2.addr0())
kono
parents:
diff changeset
320 return true;
kono
parents:
diff changeset
321 if (s2.addr0() < s1.addr0() && s2.addr0() + s2.size() > s1.addr0())
kono
parents:
diff changeset
322 return true;
kono
parents:
diff changeset
323 return false;
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325 };
kono
parents:
diff changeset
326
kono
parents:
diff changeset
327 struct ThreadSignalContext;
kono
parents:
diff changeset
328
kono
parents:
diff changeset
329 struct JmpBuf {
kono
parents:
diff changeset
330 uptr sp;
kono
parents:
diff changeset
331 uptr mangled_sp;
kono
parents:
diff changeset
332 int int_signal_send;
kono
parents:
diff changeset
333 bool in_blocking_func;
kono
parents:
diff changeset
334 uptr in_signal_handler;
kono
parents:
diff changeset
335 uptr *shadow_stack_pos;
kono
parents:
diff changeset
336 };
kono
parents:
diff changeset
337
kono
parents:
diff changeset
338 // A Processor represents a physical thread, or a P for Go.
kono
parents:
diff changeset
339 // It is used to store internal resources like allocate cache, and does not
kono
parents:
diff changeset
340 // participate in race-detection logic (invisible to end user).
kono
parents:
diff changeset
341 // In C++ it is tied to an OS thread just like ThreadState, however ideally
kono
parents:
diff changeset
342 // it should be tied to a CPU (this way we will have fewer allocator caches).
kono
parents:
diff changeset
343 // In Go it is tied to a P, so there are significantly fewer Processor's than
kono
parents:
diff changeset
344 // ThreadState's (which are tied to Gs).
kono
parents:
diff changeset
345 // A ThreadState must be wired with a Processor to handle events.
kono
parents:
diff changeset
346 struct Processor {
kono
parents:
diff changeset
347 ThreadState *thr; // currently wired thread, or nullptr
kono
parents:
diff changeset
348 #if !SANITIZER_GO
kono
parents:
diff changeset
349 AllocatorCache alloc_cache;
kono
parents:
diff changeset
350 InternalAllocatorCache internal_alloc_cache;
kono
parents:
diff changeset
351 #endif
kono
parents:
diff changeset
352 DenseSlabAllocCache block_cache;
kono
parents:
diff changeset
353 DenseSlabAllocCache sync_cache;
kono
parents:
diff changeset
354 DenseSlabAllocCache clock_cache;
kono
parents:
diff changeset
355 DDPhysicalThread *dd_pt;
kono
parents:
diff changeset
356 };
kono
parents:
diff changeset
357
kono
parents:
diff changeset
358 #if !SANITIZER_GO
kono
parents:
diff changeset
359 // ScopedGlobalProcessor temporary setups a global processor for the current
kono
parents:
diff changeset
360 // thread, if it does not have one. Intended for interceptors that can run
kono
parents:
diff changeset
361 // at the very thread end, when we already destroyed the thread processor.
kono
parents:
diff changeset
362 struct ScopedGlobalProcessor {
kono
parents:
diff changeset
363 ScopedGlobalProcessor();
kono
parents:
diff changeset
364 ~ScopedGlobalProcessor();
kono
parents:
diff changeset
365 };
kono
parents:
diff changeset
366 #endif
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 // This struct is stored in TLS.
kono
parents:
diff changeset
369 struct ThreadState {
kono
parents:
diff changeset
370 FastState fast_state;
kono
parents:
diff changeset
371 // Synch epoch represents the threads's epoch before the last synchronization
kono
parents:
diff changeset
372 // action. It allows to reduce number of shadow state updates.
kono
parents:
diff changeset
373 // For example, fast_synch_epoch=100, last write to addr X was at epoch=150,
kono
parents:
diff changeset
374 // if we are processing write to X from the same thread at epoch=200,
kono
parents:
diff changeset
375 // we do nothing, because both writes happen in the same 'synch epoch'.
kono
parents:
diff changeset
376 // That is, if another memory access does not race with the former write,
kono
parents:
diff changeset
377 // it does not race with the latter as well.
kono
parents:
diff changeset
378 // QUESTION: can we can squeeze this into ThreadState::Fast?
kono
parents:
diff changeset
379 // E.g. ThreadState::Fast is a 44-bit, 32 are taken by synch_epoch and 12 are
kono
parents:
diff changeset
380 // taken by epoch between synchs.
kono
parents:
diff changeset
381 // This way we can save one load from tls.
kono
parents:
diff changeset
382 u64 fast_synch_epoch;
kono
parents:
diff changeset
383 // This is a slow path flag. On fast path, fast_state.GetIgnoreBit() is read.
kono
parents:
diff changeset
384 // We do not distinguish beteween ignoring reads and writes
kono
parents:
diff changeset
385 // for better performance.
kono
parents:
diff changeset
386 int ignore_reads_and_writes;
kono
parents:
diff changeset
387 int ignore_sync;
kono
parents:
diff changeset
388 int suppress_reports;
kono
parents:
diff changeset
389 // Go does not support ignores.
kono
parents:
diff changeset
390 #if !SANITIZER_GO
kono
parents:
diff changeset
391 IgnoreSet mop_ignore_set;
kono
parents:
diff changeset
392 IgnoreSet sync_ignore_set;
kono
parents:
diff changeset
393 #endif
kono
parents:
diff changeset
394 // C/C++ uses fixed size shadow stack embed into Trace.
kono
parents:
diff changeset
395 // Go uses malloc-allocated shadow stack with dynamic size.
kono
parents:
diff changeset
396 uptr *shadow_stack;
kono
parents:
diff changeset
397 uptr *shadow_stack_end;
kono
parents:
diff changeset
398 uptr *shadow_stack_pos;
kono
parents:
diff changeset
399 u64 *racy_shadow_addr;
kono
parents:
diff changeset
400 u64 racy_state[2];
kono
parents:
diff changeset
401 MutexSet mset;
kono
parents:
diff changeset
402 ThreadClock clock;
kono
parents:
diff changeset
403 #if !SANITIZER_GO
kono
parents:
diff changeset
404 Vector<JmpBuf> jmp_bufs;
kono
parents:
diff changeset
405 int ignore_interceptors;
kono
parents:
diff changeset
406 #endif
kono
parents:
diff changeset
407 #if TSAN_COLLECT_STATS
kono
parents:
diff changeset
408 u64 stat[StatCnt];
kono
parents:
diff changeset
409 #endif
kono
parents:
diff changeset
410 const int tid;
kono
parents:
diff changeset
411 const int unique_id;
kono
parents:
diff changeset
412 bool in_symbolizer;
kono
parents:
diff changeset
413 bool in_ignored_lib;
kono
parents:
diff changeset
414 bool is_inited;
kono
parents:
diff changeset
415 bool is_dead;
kono
parents:
diff changeset
416 bool is_freeing;
kono
parents:
diff changeset
417 bool is_vptr_access;
kono
parents:
diff changeset
418 const uptr stk_addr;
kono
parents:
diff changeset
419 const uptr stk_size;
kono
parents:
diff changeset
420 const uptr tls_addr;
kono
parents:
diff changeset
421 const uptr tls_size;
kono
parents:
diff changeset
422 ThreadContext *tctx;
kono
parents:
diff changeset
423
kono
parents:
diff changeset
424 #if SANITIZER_DEBUG && !SANITIZER_GO
kono
parents:
diff changeset
425 InternalDeadlockDetector internal_deadlock_detector;
kono
parents:
diff changeset
426 #endif
kono
parents:
diff changeset
427 DDLogicalThread *dd_lt;
kono
parents:
diff changeset
428
kono
parents:
diff changeset
429 // Current wired Processor, or nullptr. Required to handle any events.
kono
parents:
diff changeset
430 Processor *proc1;
kono
parents:
diff changeset
431 #if !SANITIZER_GO
kono
parents:
diff changeset
432 Processor *proc() { return proc1; }
kono
parents:
diff changeset
433 #else
kono
parents:
diff changeset
434 Processor *proc();
kono
parents:
diff changeset
435 #endif
kono
parents:
diff changeset
436
kono
parents:
diff changeset
437 atomic_uintptr_t in_signal_handler;
kono
parents:
diff changeset
438 ThreadSignalContext *signal_ctx;
kono
parents:
diff changeset
439
kono
parents:
diff changeset
440 #if !SANITIZER_GO
kono
parents:
diff changeset
441 u32 last_sleep_stack_id;
kono
parents:
diff changeset
442 ThreadClock last_sleep_clock;
kono
parents:
diff changeset
443 #endif
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 // Set in regions of runtime that must be signal-safe and fork-safe.
kono
parents:
diff changeset
446 // If set, malloc must not be called.
kono
parents:
diff changeset
447 int nomalloc;
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 const ReportDesc *current_report;
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
kono
parents:
diff changeset
452 unsigned reuse_count,
kono
parents:
diff changeset
453 uptr stk_addr, uptr stk_size,
kono
parents:
diff changeset
454 uptr tls_addr, uptr tls_size);
kono
parents:
diff changeset
455 };
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 #if !SANITIZER_GO
kono
parents:
diff changeset
458 #if SANITIZER_MAC || SANITIZER_ANDROID
kono
parents:
diff changeset
459 ThreadState *cur_thread();
kono
parents:
diff changeset
460 void cur_thread_finalize();
kono
parents:
diff changeset
461 #else
kono
parents:
diff changeset
462 __attribute__((tls_model("initial-exec")))
kono
parents:
diff changeset
463 extern THREADLOCAL char cur_thread_placeholder[];
kono
parents:
diff changeset
464 INLINE ThreadState *cur_thread() {
kono
parents:
diff changeset
465 return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
kono
parents:
diff changeset
466 }
kono
parents:
diff changeset
467 INLINE void cur_thread_finalize() { }
kono
parents:
diff changeset
468 #endif // SANITIZER_MAC || SANITIZER_ANDROID
kono
parents:
diff changeset
469 #endif // SANITIZER_GO
kono
parents:
diff changeset
470
kono
parents:
diff changeset
471 class ThreadContext : public ThreadContextBase {
kono
parents:
diff changeset
472 public:
kono
parents:
diff changeset
473 explicit ThreadContext(int tid);
kono
parents:
diff changeset
474 ~ThreadContext();
kono
parents:
diff changeset
475 ThreadState *thr;
kono
parents:
diff changeset
476 u32 creation_stack_id;
kono
parents:
diff changeset
477 SyncClock sync;
kono
parents:
diff changeset
478 // Epoch at which the thread had started.
kono
parents:
diff changeset
479 // If we see an event from the thread stamped by an older epoch,
kono
parents:
diff changeset
480 // the event is from a dead thread that shared tid with this thread.
kono
parents:
diff changeset
481 u64 epoch0;
kono
parents:
diff changeset
482 u64 epoch1;
kono
parents:
diff changeset
483
kono
parents:
diff changeset
484 // Override superclass callbacks.
kono
parents:
diff changeset
485 void OnDead() override;
kono
parents:
diff changeset
486 void OnJoined(void *arg) override;
kono
parents:
diff changeset
487 void OnFinished() override;
kono
parents:
diff changeset
488 void OnStarted(void *arg) override;
kono
parents:
diff changeset
489 void OnCreated(void *arg) override;
kono
parents:
diff changeset
490 void OnReset() override;
kono
parents:
diff changeset
491 void OnDetached(void *arg) override;
kono
parents:
diff changeset
492 };
kono
parents:
diff changeset
493
kono
parents:
diff changeset
494 struct RacyStacks {
kono
parents:
diff changeset
495 MD5Hash hash[2];
kono
parents:
diff changeset
496 bool operator==(const RacyStacks &other) const {
kono
parents:
diff changeset
497 if (hash[0] == other.hash[0] && hash[1] == other.hash[1])
kono
parents:
diff changeset
498 return true;
kono
parents:
diff changeset
499 if (hash[0] == other.hash[1] && hash[1] == other.hash[0])
kono
parents:
diff changeset
500 return true;
kono
parents:
diff changeset
501 return false;
kono
parents:
diff changeset
502 }
kono
parents:
diff changeset
503 };
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 struct RacyAddress {
kono
parents:
diff changeset
506 uptr addr_min;
kono
parents:
diff changeset
507 uptr addr_max;
kono
parents:
diff changeset
508 };
kono
parents:
diff changeset
509
kono
parents:
diff changeset
510 struct FiredSuppression {
kono
parents:
diff changeset
511 ReportType type;
kono
parents:
diff changeset
512 uptr pc_or_addr;
kono
parents:
diff changeset
513 Suppression *supp;
kono
parents:
diff changeset
514 };
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 struct Context {
kono
parents:
diff changeset
517 Context();
kono
parents:
diff changeset
518
kono
parents:
diff changeset
519 bool initialized;
kono
parents:
diff changeset
520 bool after_multithreaded_fork;
kono
parents:
diff changeset
521
kono
parents:
diff changeset
522 MetaMap metamap;
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 Mutex report_mtx;
kono
parents:
diff changeset
525 int nreported;
kono
parents:
diff changeset
526 int nmissed_expected;
kono
parents:
diff changeset
527 atomic_uint64_t last_symbolize_time_ns;
kono
parents:
diff changeset
528
kono
parents:
diff changeset
529 void *background_thread;
kono
parents:
diff changeset
530 atomic_uint32_t stop_background_thread;
kono
parents:
diff changeset
531
kono
parents:
diff changeset
532 ThreadRegistry *thread_registry;
kono
parents:
diff changeset
533
kono
parents:
diff changeset
534 Mutex racy_mtx;
kono
parents:
diff changeset
535 Vector<RacyStacks> racy_stacks;
kono
parents:
diff changeset
536 Vector<RacyAddress> racy_addresses;
kono
parents:
diff changeset
537 // Number of fired suppressions may be large enough.
kono
parents:
diff changeset
538 Mutex fired_suppressions_mtx;
kono
parents:
diff changeset
539 InternalMmapVector<FiredSuppression> fired_suppressions;
kono
parents:
diff changeset
540 DDetector *dd;
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 ClockAlloc clock_alloc;
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 Flags flags;
kono
parents:
diff changeset
545
kono
parents:
diff changeset
546 u64 stat[StatCnt];
kono
parents:
diff changeset
547 u64 int_alloc_cnt[MBlockTypeCount];
kono
parents:
diff changeset
548 u64 int_alloc_siz[MBlockTypeCount];
kono
parents:
diff changeset
549 };
kono
parents:
diff changeset
550
kono
parents:
diff changeset
551 extern Context *ctx; // The one and the only global runtime context.
kono
parents:
diff changeset
552
kono
parents:
diff changeset
553 ALWAYS_INLINE Flags *flags() {
kono
parents:
diff changeset
554 return &ctx->flags;
kono
parents:
diff changeset
555 }
kono
parents:
diff changeset
556
kono
parents:
diff changeset
557 struct ScopedIgnoreInterceptors {
kono
parents:
diff changeset
558 ScopedIgnoreInterceptors() {
kono
parents:
diff changeset
559 #if !SANITIZER_GO
kono
parents:
diff changeset
560 cur_thread()->ignore_interceptors++;
kono
parents:
diff changeset
561 #endif
kono
parents:
diff changeset
562 }
kono
parents:
diff changeset
563
kono
parents:
diff changeset
564 ~ScopedIgnoreInterceptors() {
kono
parents:
diff changeset
565 #if !SANITIZER_GO
kono
parents:
diff changeset
566 cur_thread()->ignore_interceptors--;
kono
parents:
diff changeset
567 #endif
kono
parents:
diff changeset
568 }
kono
parents:
diff changeset
569 };
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 const char *GetObjectTypeFromTag(uptr tag);
kono
parents:
diff changeset
572 const char *GetReportHeaderFromTag(uptr tag);
kono
parents:
diff changeset
573 uptr TagFromShadowStackFrame(uptr pc);
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 class ScopedReport {
kono
parents:
diff changeset
576 public:
kono
parents:
diff changeset
577 explicit ScopedReport(ReportType typ, uptr tag = kExternalTagNone);
kono
parents:
diff changeset
578 ~ScopedReport();
kono
parents:
diff changeset
579
kono
parents:
diff changeset
580 void AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, StackTrace stack,
kono
parents:
diff changeset
581 const MutexSet *mset);
kono
parents:
diff changeset
582 void AddStack(StackTrace stack, bool suppressable = false);
kono
parents:
diff changeset
583 void AddThread(const ThreadContext *tctx, bool suppressable = false);
kono
parents:
diff changeset
584 void AddThread(int unique_tid, bool suppressable = false);
kono
parents:
diff changeset
585 void AddUniqueTid(int unique_tid);
kono
parents:
diff changeset
586 void AddMutex(const SyncVar *s);
kono
parents:
diff changeset
587 u64 AddMutex(u64 id);
kono
parents:
diff changeset
588 void AddLocation(uptr addr, uptr size);
kono
parents:
diff changeset
589 void AddSleep(u32 stack_id);
kono
parents:
diff changeset
590 void SetCount(int count);
kono
parents:
diff changeset
591
kono
parents:
diff changeset
592 const ReportDesc *GetReport() const;
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 private:
kono
parents:
diff changeset
595 ReportDesc *rep_;
kono
parents:
diff changeset
596 // Symbolizer makes lots of intercepted calls. If we try to process them,
kono
parents:
diff changeset
597 // at best it will cause deadlocks on internal mutexes.
kono
parents:
diff changeset
598 ScopedIgnoreInterceptors ignore_interceptors_;
kono
parents:
diff changeset
599
kono
parents:
diff changeset
600 void AddDeadMutex(u64 id);
kono
parents:
diff changeset
601
kono
parents:
diff changeset
602 ScopedReport(const ScopedReport&);
kono
parents:
diff changeset
603 void operator = (const ScopedReport&);
kono
parents:
diff changeset
604 };
kono
parents:
diff changeset
605
kono
parents:
diff changeset
606 ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
kono
parents:
diff changeset
607 void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
kono
parents:
diff changeset
608 MutexSet *mset, uptr *tag = nullptr);
kono
parents:
diff changeset
609
kono
parents:
diff changeset
610 // The stack could look like:
kono
parents:
diff changeset
611 // <start> | <main> | <foo> | tag | <bar>
kono
parents:
diff changeset
612 // This will extract the tag and keep:
kono
parents:
diff changeset
613 // <start> | <main> | <foo> | <bar>
kono
parents:
diff changeset
614 template<typename StackTraceTy>
kono
parents:
diff changeset
615 void ExtractTagFromStack(StackTraceTy *stack, uptr *tag = nullptr) {
kono
parents:
diff changeset
616 if (stack->size < 2) return;
kono
parents:
diff changeset
617 uptr possible_tag_pc = stack->trace[stack->size - 2];
kono
parents:
diff changeset
618 uptr possible_tag = TagFromShadowStackFrame(possible_tag_pc);
kono
parents:
diff changeset
619 if (possible_tag == kExternalTagNone) return;
kono
parents:
diff changeset
620 stack->trace_buffer[stack->size - 2] = stack->trace_buffer[stack->size - 1];
kono
parents:
diff changeset
621 stack->size -= 1;
kono
parents:
diff changeset
622 if (tag) *tag = possible_tag;
kono
parents:
diff changeset
623 }
kono
parents:
diff changeset
624
kono
parents:
diff changeset
625 template<typename StackTraceTy>
kono
parents:
diff changeset
626 void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack,
kono
parents:
diff changeset
627 uptr *tag = nullptr) {
kono
parents:
diff changeset
628 uptr size = thr->shadow_stack_pos - thr->shadow_stack;
kono
parents:
diff changeset
629 uptr start = 0;
kono
parents:
diff changeset
630 if (size + !!toppc > kStackTraceMax) {
kono
parents:
diff changeset
631 start = size + !!toppc - kStackTraceMax;
kono
parents:
diff changeset
632 size = kStackTraceMax - !!toppc;
kono
parents:
diff changeset
633 }
kono
parents:
diff changeset
634 stack->Init(&thr->shadow_stack[start], size, toppc);
kono
parents:
diff changeset
635 ExtractTagFromStack(stack, tag);
kono
parents:
diff changeset
636 }
kono
parents:
diff changeset
637
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 #if TSAN_COLLECT_STATS
kono
parents:
diff changeset
640 void StatAggregate(u64 *dst, u64 *src);
kono
parents:
diff changeset
641 void StatOutput(u64 *stat);
kono
parents:
diff changeset
642 #endif
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 void ALWAYS_INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
kono
parents:
diff changeset
645 #if TSAN_COLLECT_STATS
kono
parents:
diff changeset
646 thr->stat[typ] += n;
kono
parents:
diff changeset
647 #endif
kono
parents:
diff changeset
648 }
kono
parents:
diff changeset
649 void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) {
kono
parents:
diff changeset
650 #if TSAN_COLLECT_STATS
kono
parents:
diff changeset
651 thr->stat[typ] = n;
kono
parents:
diff changeset
652 #endif
kono
parents:
diff changeset
653 }
kono
parents:
diff changeset
654
kono
parents:
diff changeset
655 void MapShadow(uptr addr, uptr size);
kono
parents:
diff changeset
656 void MapThreadTrace(uptr addr, uptr size, const char *name);
kono
parents:
diff changeset
657 void DontNeedShadowFor(uptr addr, uptr size);
kono
parents:
diff changeset
658 void InitializeShadowMemory();
kono
parents:
diff changeset
659 void InitializeInterceptors();
kono
parents:
diff changeset
660 void InitializeLibIgnore();
kono
parents:
diff changeset
661 void InitializeDynamicAnnotations();
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 void ForkBefore(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
664 void ForkParentAfter(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
665 void ForkChildAfter(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
666
kono
parents:
diff changeset
667 void ReportRace(ThreadState *thr);
kono
parents:
diff changeset
668 bool OutputReport(ThreadState *thr, const ScopedReport &srep);
kono
parents:
diff changeset
669 bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace);
kono
parents:
diff changeset
670 bool IsExpectedReport(uptr addr, uptr size);
kono
parents:
diff changeset
671 void PrintMatchedBenignRaces();
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
kono
parents:
diff changeset
674 # define DPrintf Printf
kono
parents:
diff changeset
675 #else
kono
parents:
diff changeset
676 # define DPrintf(...)
kono
parents:
diff changeset
677 #endif
kono
parents:
diff changeset
678
kono
parents:
diff changeset
679 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 2
kono
parents:
diff changeset
680 # define DPrintf2 Printf
kono
parents:
diff changeset
681 #else
kono
parents:
diff changeset
682 # define DPrintf2(...)
kono
parents:
diff changeset
683 #endif
kono
parents:
diff changeset
684
kono
parents:
diff changeset
685 u32 CurrentStackId(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
686 ReportStack *SymbolizeStackId(u32 stack_id);
kono
parents:
diff changeset
687 void PrintCurrentStack(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
688 void PrintCurrentStackSlow(uptr pc); // uses libunwind
kono
parents:
diff changeset
689
kono
parents:
diff changeset
690 void Initialize(ThreadState *thr);
kono
parents:
diff changeset
691 int Finalize(ThreadState *thr);
kono
parents:
diff changeset
692
kono
parents:
diff changeset
693 void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write);
kono
parents:
diff changeset
694 void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write);
kono
parents:
diff changeset
695
kono
parents:
diff changeset
696 void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
kono
parents:
diff changeset
697 int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic);
kono
parents:
diff changeset
698 void MemoryAccessImpl(ThreadState *thr, uptr addr,
kono
parents:
diff changeset
699 int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
kono
parents:
diff changeset
700 u64 *shadow_mem, Shadow cur);
kono
parents:
diff changeset
701 void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
kono
parents:
diff changeset
702 uptr size, bool is_write);
kono
parents:
diff changeset
703 void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr,
kono
parents:
diff changeset
704 uptr size, uptr step, bool is_write);
kono
parents:
diff changeset
705 void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr,
kono
parents:
diff changeset
706 int size, bool kAccessIsWrite, bool kIsAtomic);
kono
parents:
diff changeset
707
kono
parents:
diff changeset
708 const int kSizeLog1 = 0;
kono
parents:
diff changeset
709 const int kSizeLog2 = 1;
kono
parents:
diff changeset
710 const int kSizeLog4 = 2;
kono
parents:
diff changeset
711 const int kSizeLog8 = 3;
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 void ALWAYS_INLINE MemoryRead(ThreadState *thr, uptr pc,
kono
parents:
diff changeset
714 uptr addr, int kAccessSizeLog) {
kono
parents:
diff changeset
715 MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false);
kono
parents:
diff changeset
716 }
kono
parents:
diff changeset
717
kono
parents:
diff changeset
718 void ALWAYS_INLINE MemoryWrite(ThreadState *thr, uptr pc,
kono
parents:
diff changeset
719 uptr addr, int kAccessSizeLog) {
kono
parents:
diff changeset
720 MemoryAccess(thr, pc, addr, kAccessSizeLog, true, false);
kono
parents:
diff changeset
721 }
kono
parents:
diff changeset
722
kono
parents:
diff changeset
723 void ALWAYS_INLINE MemoryReadAtomic(ThreadState *thr, uptr pc,
kono
parents:
diff changeset
724 uptr addr, int kAccessSizeLog) {
kono
parents:
diff changeset
725 MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true);
kono
parents:
diff changeset
726 }
kono
parents:
diff changeset
727
kono
parents:
diff changeset
728 void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
kono
parents:
diff changeset
729 uptr addr, int kAccessSizeLog) {
kono
parents:
diff changeset
730 MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true);
kono
parents:
diff changeset
731 }
kono
parents:
diff changeset
732
kono
parents:
diff changeset
733 void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
kono
parents:
diff changeset
734 void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
kono
parents:
diff changeset
735 void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
kono
parents:
diff changeset
736
kono
parents:
diff changeset
737 void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack = true);
kono
parents:
diff changeset
738 void ThreadIgnoreEnd(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
739 void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc, bool save_stack = true);
kono
parents:
diff changeset
740 void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
741
kono
parents:
diff changeset
742 void FuncEntry(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
743 void FuncExit(ThreadState *thr);
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
kono
parents:
diff changeset
746 void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread);
kono
parents:
diff changeset
747 void ThreadFinish(ThreadState *thr);
kono
parents:
diff changeset
748 int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
kono
parents:
diff changeset
749 void ThreadJoin(ThreadState *thr, uptr pc, int tid);
kono
parents:
diff changeset
750 void ThreadDetach(ThreadState *thr, uptr pc, int tid);
kono
parents:
diff changeset
751 void ThreadFinalize(ThreadState *thr);
kono
parents:
diff changeset
752 void ThreadSetName(ThreadState *thr, const char *name);
kono
parents:
diff changeset
753 int ThreadCount(ThreadState *thr);
kono
parents:
diff changeset
754 void ProcessPendingSignals(ThreadState *thr);
kono
parents:
diff changeset
755
kono
parents:
diff changeset
756 Processor *ProcCreate();
kono
parents:
diff changeset
757 void ProcDestroy(Processor *proc);
kono
parents:
diff changeset
758 void ProcWire(Processor *proc, ThreadState *thr);
kono
parents:
diff changeset
759 void ProcUnwire(Processor *proc, ThreadState *thr);
kono
parents:
diff changeset
760
kono
parents:
diff changeset
761 // Note: the parameter is called flagz, because flags is already taken
kono
parents:
diff changeset
762 // by the global function that returns flags.
kono
parents:
diff changeset
763 void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
kono
parents:
diff changeset
764 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
kono
parents:
diff changeset
765 void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
kono
parents:
diff changeset
766 void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0,
kono
parents:
diff changeset
767 int rec = 1);
kono
parents:
diff changeset
768 int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
kono
parents:
diff changeset
769 void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
kono
parents:
diff changeset
770 void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
kono
parents:
diff changeset
771 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
kono
parents:
diff changeset
772 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
kono
parents:
diff changeset
773 void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
kono
parents:
diff changeset
774 void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr);
kono
parents:
diff changeset
775
kono
parents:
diff changeset
776 void Acquire(ThreadState *thr, uptr pc, uptr addr);
kono
parents:
diff changeset
777 // AcquireGlobal synchronizes the current thread with all other threads.
kono
parents:
diff changeset
778 // In terms of happens-before relation, it draws a HB edge from all threads
kono
parents:
diff changeset
779 // (where they happen to execute right now) to the current thread. We use it to
kono
parents:
diff changeset
780 // handle Go finalizers. Namely, finalizer goroutine executes AcquireGlobal
kono
parents:
diff changeset
781 // right before executing finalizers. This provides a coarse, but simple
kono
parents:
diff changeset
782 // approximation of the actual required synchronization.
kono
parents:
diff changeset
783 void AcquireGlobal(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
784 void Release(ThreadState *thr, uptr pc, uptr addr);
kono
parents:
diff changeset
785 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
kono
parents:
diff changeset
786 void AfterSleep(ThreadState *thr, uptr pc);
kono
parents:
diff changeset
787 void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c);
kono
parents:
diff changeset
788 void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
kono
parents:
diff changeset
789 void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c);
kono
parents:
diff changeset
790 void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
kono
parents:
diff changeset
791
kono
parents:
diff changeset
792 // The hacky call uses custom calling convention and an assembly thunk.
kono
parents:
diff changeset
793 // It is considerably faster that a normal call for the caller
kono
parents:
diff changeset
794 // if it is not executed (it is intended for slow paths from hot functions).
kono
parents:
diff changeset
795 // The trick is that the call preserves all registers and the compiler
kono
parents:
diff changeset
796 // does not treat it as a call.
kono
parents:
diff changeset
797 // If it does not work for you, use normal call.
kono
parents:
diff changeset
798 #if !SANITIZER_DEBUG && defined(__x86_64__) && !SANITIZER_MAC
kono
parents:
diff changeset
799 // The caller may not create the stack frame for itself at all,
kono
parents:
diff changeset
800 // so we create a reserve stack frame for it (1024b must be enough).
kono
parents:
diff changeset
801 #define HACKY_CALL(f) \
kono
parents:
diff changeset
802 __asm__ __volatile__("sub $1024, %%rsp;" \
kono
parents:
diff changeset
803 CFI_INL_ADJUST_CFA_OFFSET(1024) \
kono
parents:
diff changeset
804 ".hidden " #f "_thunk;" \
kono
parents:
diff changeset
805 "call " #f "_thunk;" \
kono
parents:
diff changeset
806 "add $1024, %%rsp;" \
kono
parents:
diff changeset
807 CFI_INL_ADJUST_CFA_OFFSET(-1024) \
kono
parents:
diff changeset
808 ::: "memory", "cc");
kono
parents:
diff changeset
809 #else
kono
parents:
diff changeset
810 #define HACKY_CALL(f) f()
kono
parents:
diff changeset
811 #endif
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 void TraceSwitch(ThreadState *thr);
kono
parents:
diff changeset
814 uptr TraceTopPC(ThreadState *thr);
kono
parents:
diff changeset
815 uptr TraceSize();
kono
parents:
diff changeset
816 uptr TraceParts();
kono
parents:
diff changeset
817 Trace *ThreadTrace(int tid);
kono
parents:
diff changeset
818
kono
parents:
diff changeset
819 extern "C" void __tsan_trace_switch();
kono
parents:
diff changeset
820 void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
kono
parents:
diff changeset
821 EventType typ, u64 addr) {
kono
parents:
diff changeset
822 if (!kCollectHistory)
kono
parents:
diff changeset
823 return;
kono
parents:
diff changeset
824 DCHECK_GE((int)typ, 0);
kono
parents:
diff changeset
825 DCHECK_LE((int)typ, 7);
kono
parents:
diff changeset
826 DCHECK_EQ(GetLsb(addr, kEventPCBits), addr);
kono
parents:
diff changeset
827 StatInc(thr, StatEvents);
kono
parents:
diff changeset
828 u64 pos = fs.GetTracePos();
kono
parents:
diff changeset
829 if (UNLIKELY((pos % kTracePartSize) == 0)) {
kono
parents:
diff changeset
830 #if !SANITIZER_GO
kono
parents:
diff changeset
831 HACKY_CALL(__tsan_trace_switch);
kono
parents:
diff changeset
832 #else
kono
parents:
diff changeset
833 TraceSwitch(thr);
kono
parents:
diff changeset
834 #endif
kono
parents:
diff changeset
835 }
kono
parents:
diff changeset
836 Event *trace = (Event*)GetThreadTrace(fs.tid());
kono
parents:
diff changeset
837 Event *evp = &trace[pos];
kono
parents:
diff changeset
838 Event ev = (u64)addr | ((u64)typ << kEventPCBits);
kono
parents:
diff changeset
839 *evp = ev;
kono
parents:
diff changeset
840 }
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842 #if !SANITIZER_GO
kono
parents:
diff changeset
843 uptr ALWAYS_INLINE HeapEnd() {
kono
parents:
diff changeset
844 return HeapMemEnd() + PrimaryAllocator::AdditionalSize();
kono
parents:
diff changeset
845 }
kono
parents:
diff changeset
846 #endif
kono
parents:
diff changeset
847
kono
parents:
diff changeset
848 } // namespace __tsan
kono
parents:
diff changeset
849
kono
parents:
diff changeset
850 #endif // TSAN_RTL_H