1 //===-- tsan_sync.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 (TSan), a race detector. 9 // 10 //===----------------------------------------------------------------------===// 11 #include "sanitizer_common/sanitizer_placement_new.h" 12 #include "tsan_sync.h" 13 #include "tsan_rtl.h" 14 #include "tsan_mman.h" 15 16 namespace __tsan { 17 18 SyncVar::SyncVar(uptr addr, u64 uid) 19 : mtx(MutexTypeSyncVar, StatMtxSyncVar) 20 , addr(addr) 21 , uid(uid) 22 , owner_tid(kInvalidTid) 23 , last_lock() 24 , recursion() 25 , is_rw() 26 , is_recursive() 27 , is_broken() 28 , is_linker_init() { 29 } 30 31 SyncTab::Part::Part() 32 : mtx(MutexTypeSyncTab, StatMtxSyncTab) 33 , val() { 34 } 35 36 SyncTab::SyncTab() { 37 } 38 39 SyncTab::~SyncTab() { 40 for (int i = 0; i < kPartCount; i++) { 41 while (tab_[i].val) { 42 SyncVar *tmp = tab_[i].val; 43 tab_[i].val = tmp->next; 44 DestroyAndFree(tmp); 45 } 46 } 47 } 48 49 SyncVar* SyncTab::GetOrCreateAndLock(ThreadState *thr, uptr pc, 50 uptr addr, bool write_lock) { 51 return GetAndLock(thr, pc, addr, write_lock, true); 52 } 53 54 SyncVar* SyncTab::GetIfExistsAndLock(uptr addr, bool write_lock) { 55 return GetAndLock(0, 0, addr, write_lock, false); 56 } 57 58 SyncVar* SyncTab::Create(ThreadState *thr, uptr pc, uptr addr) { 59 StatInc(thr, StatSyncCreated); 60 void *mem = internal_alloc(MBlockSync, sizeof(SyncVar)); 61 const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed); 62 SyncVar *res = new(mem) SyncVar(addr, uid); 63 #ifndef TSAN_GO 64 res->creation_stack.ObtainCurrent(thr, pc); 65 #endif 66 return res; 67 } 68 69 SyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc, 70 uptr addr, bool write_lock, bool create) { 71 #ifndef TSAN_GO 72 { // NOLINT 73 SyncVar *res = GetJavaSync(thr, pc, addr, write_lock, create); 74 if (res) 75 return res; 76 } 77 78 // Here we ask only PrimaryAllocator, because 79 // SecondaryAllocator::PointerIsMine() is slow and we have fallback on 80 // the hashmap anyway. 81 if (PrimaryAllocator::PointerIsMine((void*)addr)) { 82 MBlock *b = user_mblock(thr, (void*)addr); 83 Lock l(&b->mtx); 84 SyncVar *res = 0; 85 for (res = b->head; res; res = res->next) { 86 if (res->addr == addr) 87 break; 88 } 89 if (res == 0) { 90 if (!create) 91 return 0; 92 res = Create(thr, pc, addr); 93 res->next = b->head; 94 b->head = res; 95 } 96 if (write_lock) 97 res->mtx.Lock(); 98 else 99 res->mtx.ReadLock(); 100 return res; 101 } 102 #endif 103 104 Part *p = &tab_[PartIdx(addr)]; 105 { 106 ReadLock l(&p->mtx); 107 for (SyncVar *res = p->val; res; res = res->next) { 108 if (res->addr == addr) { 109 if (write_lock) 110 res->mtx.Lock(); 111 else 112 res->mtx.ReadLock(); 113 return res; 114 } 115 } 116 } 117 if (!create) 118 return 0; 119 { 120 Lock l(&p->mtx); 121 SyncVar *res = p->val; 122 for (; res; res = res->next) { 123 if (res->addr == addr) 124 break; 125 } 126 if (res == 0) { 127 res = Create(thr, pc, addr); 128 res->next = p->val; 129 p->val = res; 130 } 131 if (write_lock) 132 res->mtx.Lock(); 133 else 134 res->mtx.ReadLock(); 135 return res; 136 } 137 } 138 139 SyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) { 140 #ifndef TSAN_GO 141 { // NOLINT 142 SyncVar *res = GetAndRemoveJavaSync(thr, pc, addr); 143 if (res) 144 return res; 145 } 146 if (PrimaryAllocator::PointerIsMine((void*)addr)) { 147 MBlock *b = user_mblock(thr, (void*)addr); 148 SyncVar *res = 0; 149 { 150 Lock l(&b->mtx); 151 SyncVar **prev = &b->head; 152 res = *prev; 153 while (res) { 154 if (res->addr == addr) { 155 if (res->is_linker_init) 156 return 0; 157 *prev = res->next; 158 break; 159 } 160 prev = &res->next; 161 res = *prev; 162 } 163 } 164 if (res) { 165 StatInc(thr, StatSyncDestroyed); 166 res->mtx.Lock(); 167 res->mtx.Unlock(); 168 } 169 return res; 170 } 171 #endif 172 173 Part *p = &tab_[PartIdx(addr)]; 174 SyncVar *res = 0; 175 { 176 Lock l(&p->mtx); 177 SyncVar **prev = &p->val; 178 res = *prev; 179 while (res) { 180 if (res->addr == addr) { 181 if (res->is_linker_init) 182 return 0; 183 *prev = res->next; 184 break; 185 } 186 prev = &res->next; 187 res = *prev; 188 } 189 } 190 if (res) { 191 StatInc(thr, StatSyncDestroyed); 192 res->mtx.Lock(); 193 res->mtx.Unlock(); 194 } 195 return res; 196 } 197 198 uptr SyncVar::GetMemoryConsumption() { 199 return sizeof(*this) 200 + clock.size() * sizeof(u64) 201 + read_clock.size() * sizeof(u64) 202 + creation_stack.Size() * sizeof(uptr); 203 } 204 205 uptr SyncTab::GetMemoryConsumption(uptr *nsync) { 206 uptr mem = 0; 207 for (int i = 0; i < kPartCount; i++) { 208 Part *p = &tab_[i]; 209 Lock l(&p->mtx); 210 for (SyncVar *s = p->val; s; s = s->next) { 211 *nsync += 1; 212 mem += s->GetMemoryConsumption(); 213 } 214 } 215 return mem; 216 } 217 218 int SyncTab::PartIdx(uptr addr) { 219 return (addr >> 3) % kPartCount; 220 } 221 222 StackTrace::StackTrace() 223 : n_() 224 , s_() 225 , c_() { 226 } 227 228 StackTrace::StackTrace(uptr *buf, uptr cnt) 229 : n_() 230 , s_(buf) 231 , c_(cnt) { 232 CHECK_NE(buf, 0); 233 CHECK_NE(cnt, 0); 234 } 235 236 StackTrace::~StackTrace() { 237 Reset(); 238 } 239 240 void StackTrace::Reset() { 241 if (s_ && !c_) { 242 CHECK_NE(n_, 0); 243 internal_free(s_); 244 s_ = 0; 245 } 246 n_ = 0; 247 } 248 249 void StackTrace::Init(const uptr *pcs, uptr cnt) { 250 Reset(); 251 if (cnt == 0) 252 return; 253 if (c_) { 254 CHECK_NE(s_, 0); 255 CHECK_LE(cnt, c_); 256 } else { 257 s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0])); 258 } 259 n_ = cnt; 260 internal_memcpy(s_, pcs, cnt * sizeof(s_[0])); 261 } 262 263 void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) { 264 Reset(); 265 n_ = thr->shadow_stack_pos - thr->shadow_stack; 266 if (n_ + !!toppc == 0) 267 return; 268 uptr start = 0; 269 if (c_) { 270 CHECK_NE(s_, 0); 271 if (n_ + !!toppc > c_) { 272 start = n_ - c_ + !!toppc; 273 n_ = c_ - !!toppc; 274 } 275 } else { 276 s_ = (uptr*)internal_alloc(MBlockStackTrace, 277 (n_ + !!toppc) * sizeof(s_[0])); 278 } 279 for (uptr i = 0; i < n_; i++) 280 s_[i] = thr->shadow_stack[start + i]; 281 if (toppc) { 282 s_[n_] = toppc; 283 n_++; 284 } 285 } 286 287 void StackTrace::CopyFrom(const StackTrace& other) { 288 Reset(); 289 Init(other.Begin(), other.Size()); 290 } 291 292 bool StackTrace::IsEmpty() const { 293 return n_ == 0; 294 } 295 296 uptr StackTrace::Size() const { 297 return n_; 298 } 299 300 uptr StackTrace::Get(uptr i) const { 301 CHECK_LT(i, n_); 302 return s_[i]; 303 } 304 305 const uptr *StackTrace::Begin() const { 306 return s_; 307 } 308 309 } // namespace __tsan 310