xref: /freebsd/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_defs.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1 //===-- tsan_defs.h ---------------------------------------------*- C++ -*-===//
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 #ifndef TSAN_DEFS_H
14 #define TSAN_DEFS_H
15 
16 #include "sanitizer_common/sanitizer_internal_defs.h"
17 #include "sanitizer_common/sanitizer_libc.h"
18 #include "tsan_stat.h"
19 #include "ubsan/ubsan_platform.h"
20 
21 // Setup defaults for compile definitions.
22 #ifndef TSAN_NO_HISTORY
23 # define TSAN_NO_HISTORY 0
24 #endif
25 
26 #ifndef TSAN_COLLECT_STATS
27 # define TSAN_COLLECT_STATS 0
28 #endif
29 
30 #ifndef TSAN_CONTAINS_UBSAN
31 # if CAN_SANITIZE_UB && !SANITIZER_GO
32 #  define TSAN_CONTAINS_UBSAN 1
33 # else
34 #  define TSAN_CONTAINS_UBSAN 0
35 # endif
36 #endif
37 
38 namespace __tsan {
39 
40 const int kClkBits = 42;
41 const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
42 
43 struct ClockElem {
44   u64 epoch  : kClkBits;
45   u64 reused : 64 - kClkBits;  // tid reuse count
46 };
47 
48 struct ClockBlock {
49   static const uptr kSize = 512;
50   static const uptr kTableSize = kSize / sizeof(u32);
51   static const uptr kClockCount = kSize / sizeof(ClockElem);
52   static const uptr kRefIdx = kTableSize - 1;
53   static const uptr kBlockIdx = kTableSize - 2;
54 
55   union {
56     u32       table[kTableSize];
57     ClockElem clock[kClockCount];
58   };
59 
60   ClockBlock() {
61   }
62 };
63 
64 const int kTidBits = 13;
65 // Reduce kMaxTid by kClockCount because one slot in ClockBlock table is
66 // occupied by reference counter, so total number of elements we can store
67 // in SyncClock is kClockCount * (kTableSize - 1).
68 const unsigned kMaxTid = (1 << kTidBits) - ClockBlock::kClockCount;
69 #if !SANITIZER_GO
70 const unsigned kMaxTidInClock = kMaxTid * 2;  // This includes msb 'freed' bit.
71 #else
72 const unsigned kMaxTidInClock = kMaxTid;  // Go does not track freed memory.
73 #endif
74 const uptr kShadowStackSize = 64 * 1024;
75 
76 // Count of shadow values in a shadow cell.
77 const uptr kShadowCnt = 4;
78 
79 // That many user bytes are mapped onto a single shadow cell.
80 const uptr kShadowCell = 8;
81 
82 // Size of a single shadow value (u64).
83 const uptr kShadowSize = 8;
84 
85 // Shadow memory is kShadowMultiplier times larger than user memory.
86 const uptr kShadowMultiplier = kShadowSize * kShadowCnt / kShadowCell;
87 
88 // That many user bytes are mapped onto a single meta shadow cell.
89 // Must be less or equal to minimal memory allocator alignment.
90 const uptr kMetaShadowCell = 8;
91 
92 // Size of a single meta shadow value (u32).
93 const uptr kMetaShadowSize = 4;
94 
95 #if TSAN_NO_HISTORY
96 const bool kCollectHistory = false;
97 #else
98 const bool kCollectHistory = true;
99 #endif
100 
101 const u16 kInvalidTid = kMaxTid + 1;
102 
103 // The following "build consistency" machinery ensures that all source files
104 // are built in the same configuration. Inconsistent builds lead to
105 // hard to debug crashes.
106 #if SANITIZER_DEBUG
107 void build_consistency_debug();
108 #else
109 void build_consistency_release();
110 #endif
111 
112 #if TSAN_COLLECT_STATS
113 void build_consistency_stats();
114 #else
115 void build_consistency_nostats();
116 #endif
117 
118 static inline void USED build_consistency() {
119 #if SANITIZER_DEBUG
120   build_consistency_debug();
121 #else
122   build_consistency_release();
123 #endif
124 #if TSAN_COLLECT_STATS
125   build_consistency_stats();
126 #else
127   build_consistency_nostats();
128 #endif
129 }
130 
131 template<typename T>
132 T min(T a, T b) {
133   return a < b ? a : b;
134 }
135 
136 template<typename T>
137 T max(T a, T b) {
138   return a > b ? a : b;
139 }
140 
141 template<typename T>
142 T RoundUp(T p, u64 align) {
143   DCHECK_EQ(align & (align - 1), 0);
144   return (T)(((u64)p + align - 1) & ~(align - 1));
145 }
146 
147 template<typename T>
148 T RoundDown(T p, u64 align) {
149   DCHECK_EQ(align & (align - 1), 0);
150   return (T)((u64)p & ~(align - 1));
151 }
152 
153 // Zeroizes high part, returns 'bits' lsb bits.
154 template<typename T>
155 T GetLsb(T v, int bits) {
156   return (T)((u64)v & ((1ull << bits) - 1));
157 }
158 
159 struct MD5Hash {
160   u64 hash[2];
161   bool operator==(const MD5Hash &other) const;
162 };
163 
164 MD5Hash md5_hash(const void *data, uptr size);
165 
166 struct Processor;
167 struct ThreadState;
168 class ThreadContext;
169 struct Context;
170 struct ReportStack;
171 class ReportDesc;
172 class RegionAlloc;
173 
174 // Descriptor of user's memory block.
175 struct MBlock {
176   u64  siz : 48;
177   u64  tag : 16;
178   u32  stk;
179   u16  tid;
180 };
181 
182 COMPILER_CHECK(sizeof(MBlock) == 16);
183 
184 enum ExternalTag : uptr {
185   kExternalTagNone = 0,
186   kExternalTagSwiftModifyingAccess = 1,
187   kExternalTagFirstUserAvailable = 2,
188   kExternalTagMax = 1024,
189   // Don't set kExternalTagMax over 65,536, since MBlock only stores tags
190   // as 16-bit values, see tsan_defs.h.
191 };
192 
193 }  // namespace __tsan
194 
195 #endif  // TSAN_DEFS_H
196