1 //===-- tsan_rtl_thread.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 "sanitizer_common/sanitizer_placement_new.h"
14 #include "tsan_rtl.h"
15 #include "tsan_mman.h"
16 #include "tsan_platform.h"
17 #include "tsan_report.h"
18 #include "tsan_sync.h"
19 
20 namespace __tsan {
21 
22 // ThreadContext implementation.
23 
24 ThreadContext::ThreadContext(Tid tid)
25     : ThreadContextBase(tid), thr(), sync(), epoch0(), epoch1() {}
26 
27 #if !SANITIZER_GO
28 ThreadContext::~ThreadContext() {
29 }
30 #endif
31 
32 void ThreadContext::OnReset() {
33   CHECK_EQ(sync.size(), 0);
34   uptr trace_p = GetThreadTrace(tid);
35   ReleaseMemoryPagesToOS(trace_p, trace_p + TraceSize() * sizeof(Event));
36   //!!! ReleaseMemoryToOS(GetThreadTraceHeader(tid), sizeof(Trace));
37 }
38 
39 #if !SANITIZER_GO
40 struct ThreadLeak {
41   ThreadContext *tctx;
42   int count;
43 };
44 
45 static void CollectThreadLeaks(ThreadContextBase *tctx_base, void *arg) {
46   auto &leaks = *static_cast<Vector<ThreadLeak> *>(arg);
47   auto *tctx = static_cast<ThreadContext *>(tctx_base);
48   if (tctx->detached || tctx->status != ThreadStatusFinished)
49     return;
50   for (uptr i = 0; i < leaks.Size(); i++) {
51     if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {
52       leaks[i].count++;
53       return;
54     }
55   }
56   leaks.PushBack({tctx, 1});
57 }
58 #endif
59 
60 #if !SANITIZER_GO
61 static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
62   if (tctx->tid == kMainTid) {
63     Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
64   } else {
65     Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
66       " created at:\n", tctx->tid, tctx->name);
67     PrintStack(SymbolizeStackId(tctx->creation_stack_id));
68   }
69   Printf("  One of the following ignores was not ended"
70       " (in order of probability)\n");
71   for (uptr i = 0; i < set->Size(); i++) {
72     Printf("  Ignore was enabled at:\n");
73     PrintStack(SymbolizeStackId(set->At(i)));
74   }
75   Die();
76 }
77 
78 static void ThreadCheckIgnore(ThreadState *thr) {
79   if (ctx->after_multithreaded_fork)
80     return;
81   if (thr->ignore_reads_and_writes)
82     ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
83   if (thr->ignore_sync)
84     ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
85 }
86 #else
87 static void ThreadCheckIgnore(ThreadState *thr) {}
88 #endif
89 
90 void ThreadFinalize(ThreadState *thr) {
91   ThreadCheckIgnore(thr);
92 #if !SANITIZER_GO
93   if (!ShouldReport(thr, ReportTypeThreadLeak))
94     return;
95   ThreadRegistryLock l(&ctx->thread_registry);
96   Vector<ThreadLeak> leaks;
97   ctx->thread_registry.RunCallbackForEachThreadLocked(CollectThreadLeaks,
98                                                       &leaks);
99   for (uptr i = 0; i < leaks.Size(); i++) {
100     ScopedReport rep(ReportTypeThreadLeak);
101     rep.AddThread(leaks[i].tctx, true);
102     rep.SetCount(leaks[i].count);
103     OutputReport(thr, rep);
104   }
105 #endif
106 }
107 
108 int ThreadCount(ThreadState *thr) {
109   uptr result;
110   ctx->thread_registry.GetNumberOfThreads(0, 0, &result);
111   return (int)result;
112 }
113 
114 struct OnCreatedArgs {
115   ThreadState *thr;
116   uptr pc;
117 };
118 
119 Tid ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
120   OnCreatedArgs args = { thr, pc };
121   u32 parent_tid = thr ? thr->tid : kInvalidTid;  // No parent for GCD workers.
122   Tid tid = ctx->thread_registry.CreateThread(uid, detached, parent_tid, &args);
123   DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", parent_tid, tid, uid);
124   return tid;
125 }
126 
127 void ThreadContext::OnCreated(void *arg) {
128   thr = 0;
129   if (tid == kMainTid)
130     return;
131   OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
132   if (!args->thr)  // GCD workers don't have a parent thread.
133     return;
134   args->thr->fast_state.IncrementEpoch();
135   // Can't increment epoch w/o writing to the trace as well.
136   TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
137   ReleaseImpl(args->thr, 0, &sync);
138   creation_stack_id = CurrentStackId(args->thr, args->pc);
139 }
140 
141 struct OnStartedArgs {
142   ThreadState *thr;
143   uptr stk_addr;
144   uptr stk_size;
145   uptr tls_addr;
146   uptr tls_size;
147 };
148 
149 void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
150                  ThreadType thread_type) {
151   uptr stk_addr = 0;
152   uptr stk_size = 0;
153   uptr tls_addr = 0;
154   uptr tls_size = 0;
155 #if !SANITIZER_GO
156   if (thread_type != ThreadType::Fiber)
157     GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
158                          &tls_size);
159 
160   if (tid != kMainTid) {
161     if (stk_addr && stk_size)
162       MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
163 
164     if (tls_addr && tls_size) ImitateTlsWrite(thr, tls_addr, tls_size);
165   }
166 #endif
167 
168   ThreadRegistry *tr = &ctx->thread_registry;
169   OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
170   tr->StartThread(tid, os_id, thread_type, &args);
171 
172   while (!thr->tctx->trace.parts.Empty()) thr->tctx->trace.parts.PopBack();
173 
174 #if !SANITIZER_GO
175   if (ctx->after_multithreaded_fork) {
176     thr->ignore_interceptors++;
177     ThreadIgnoreBegin(thr, 0);
178     ThreadIgnoreSyncBegin(thr, 0);
179   }
180 #endif
181 }
182 
183 void ThreadContext::OnStarted(void *arg) {
184   OnStartedArgs *args = static_cast<OnStartedArgs *>(arg);
185   thr = args->thr;
186   // RoundUp so that one trace part does not contain events
187   // from different threads.
188   epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
189   epoch1 = (u64)-1;
190   new (thr)
191       ThreadState(ctx, tid, unique_id, epoch0, reuse_count, args->stk_addr,
192                   args->stk_size, args->tls_addr, args->tls_size);
193 #if !SANITIZER_GO
194   thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
195   thr->shadow_stack_pos = thr->shadow_stack;
196   thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
197 #else
198   // Setup dynamic shadow stack.
199   const int kInitStackSize = 8;
200   thr->shadow_stack = (uptr *)Alloc(kInitStackSize * sizeof(uptr));
201   thr->shadow_stack_pos = thr->shadow_stack;
202   thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
203 #endif
204   if (common_flags()->detect_deadlocks)
205     thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id);
206   thr->fast_state.SetHistorySize(flags()->history_size);
207   // Commit switch to the new part of the trace.
208   // TraceAddEvent will reset stack0/mset0 in the new part for us.
209   TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
210 
211   thr->fast_synch_epoch = epoch0;
212   AcquireImpl(thr, 0, &sync);
213   sync.Reset(&thr->proc()->clock_cache);
214   thr->tctx = this;
215   thr->is_inited = true;
216   DPrintf(
217       "#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
218       "tls_addr=%zx tls_size=%zx\n",
219       tid, (uptr)epoch0, args->stk_addr, args->stk_size, args->tls_addr,
220       args->tls_size);
221 }
222 
223 void ThreadFinish(ThreadState *thr) {
224   ThreadCheckIgnore(thr);
225   if (thr->stk_addr && thr->stk_size)
226     DontNeedShadowFor(thr->stk_addr, thr->stk_size);
227   if (thr->tls_addr && thr->tls_size)
228     DontNeedShadowFor(thr->tls_addr, thr->tls_size);
229   thr->is_dead = true;
230   ctx->thread_registry.FinishThread(thr->tid);
231 }
232 
233 void ThreadContext::OnFinished() {
234 #if SANITIZER_GO
235   Free(thr->shadow_stack);
236   thr->shadow_stack_pos = nullptr;
237   thr->shadow_stack_end = nullptr;
238 #endif
239   if (!detached) {
240     thr->fast_state.IncrementEpoch();
241     // Can't increment epoch w/o writing to the trace as well.
242     TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
243     ReleaseImpl(thr, 0, &sync);
244   }
245   epoch1 = thr->fast_state.epoch();
246 
247   if (common_flags()->detect_deadlocks)
248     ctx->dd->DestroyLogicalThread(thr->dd_lt);
249   thr->clock.ResetCached(&thr->proc()->clock_cache);
250 #if !SANITIZER_GO
251   thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache);
252 #endif
253 #if !SANITIZER_GO
254   PlatformCleanUpThreadState(thr);
255 #endif
256   thr->~ThreadState();
257   thr = 0;
258 }
259 
260 struct ConsumeThreadContext {
261   uptr uid;
262   ThreadContextBase *tctx;
263 };
264 
265 static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
266   ConsumeThreadContext *findCtx = (ConsumeThreadContext *)arg;
267   if (tctx->user_id == findCtx->uid && tctx->status != ThreadStatusInvalid) {
268     if (findCtx->tctx) {
269       // Ensure that user_id is unique. If it's not the case we are screwed.
270       // Something went wrong before, but now there is no way to recover.
271       // Returning a wrong thread is not an option, it may lead to very hard
272       // to debug false positives (e.g. if we join a wrong thread).
273       Report("ThreadSanitizer: dup thread with used id 0x%zx\n", findCtx->uid);
274       Die();
275     }
276     findCtx->tctx = tctx;
277     tctx->user_id = 0;
278   }
279   return false;
280 }
281 
282 Tid ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) {
283   ConsumeThreadContext findCtx = {uid, nullptr};
284   ctx->thread_registry.FindThread(ConsumeThreadByUid, &findCtx);
285   Tid tid = findCtx.tctx ? findCtx.tctx->tid : kInvalidTid;
286   DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
287   return tid;
288 }
289 
290 void ThreadJoin(ThreadState *thr, uptr pc, Tid tid) {
291   CHECK_GT(tid, 0);
292   CHECK_LT(tid, kMaxTid);
293   DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
294   ctx->thread_registry.JoinThread(tid, thr);
295 }
296 
297 void ThreadContext::OnJoined(void *arg) {
298   ThreadState *caller_thr = static_cast<ThreadState *>(arg);
299   AcquireImpl(caller_thr, 0, &sync);
300   sync.Reset(&caller_thr->proc()->clock_cache);
301 }
302 
303 void ThreadContext::OnDead() { CHECK_EQ(sync.size(), 0); }
304 
305 void ThreadDetach(ThreadState *thr, uptr pc, Tid tid) {
306   CHECK_GT(tid, 0);
307   CHECK_LT(tid, kMaxTid);
308   ctx->thread_registry.DetachThread(tid, thr);
309 }
310 
311 void ThreadContext::OnDetached(void *arg) {
312   ThreadState *thr1 = static_cast<ThreadState *>(arg);
313   sync.Reset(&thr1->proc()->clock_cache);
314 }
315 
316 void ThreadNotJoined(ThreadState *thr, uptr pc, Tid tid, uptr uid) {
317   CHECK_GT(tid, 0);
318   CHECK_LT(tid, kMaxTid);
319   ctx->thread_registry.SetThreadUserId(tid, uid);
320 }
321 
322 void ThreadSetName(ThreadState *thr, const char *name) {
323   ctx->thread_registry.SetThreadName(thr->tid, name);
324 }
325 
326 void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
327                        uptr size, bool is_write) {
328   if (size == 0)
329     return;
330 
331   RawShadow *shadow_mem = MemToShadow(addr);
332   DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n",
333       thr->tid, (void*)pc, (void*)addr,
334       (int)size, is_write);
335 
336 #if SANITIZER_DEBUG
337   if (!IsAppMem(addr)) {
338     Printf("Access to non app mem %zx\n", addr);
339     DCHECK(IsAppMem(addr));
340   }
341   if (!IsAppMem(addr + size - 1)) {
342     Printf("Access to non app mem %zx\n", addr + size - 1);
343     DCHECK(IsAppMem(addr + size - 1));
344   }
345   if (!IsShadowMem(shadow_mem)) {
346     Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
347     DCHECK(IsShadowMem(shadow_mem));
348   }
349   if (!IsShadowMem(shadow_mem + size * kShadowCnt / 8 - 1)) {
350     Printf("Bad shadow addr %p (%zx)\n",
351                shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
352     DCHECK(IsShadowMem(shadow_mem + size * kShadowCnt / 8 - 1));
353   }
354 #endif
355 
356   if (*shadow_mem == kShadowRodata) {
357     DCHECK(!is_write);
358     // Access to .rodata section, no races here.
359     // Measurements show that it can be 10-20% of all memory accesses.
360     return;
361   }
362 
363   FastState fast_state = thr->fast_state;
364   if (fast_state.GetIgnoreBit())
365     return;
366 
367   fast_state.IncrementEpoch();
368   thr->fast_state = fast_state;
369   TraceAddEvent(thr, fast_state, EventTypeMop, pc);
370 
371   bool unaligned = (addr % kShadowCell) != 0;
372 
373   // Handle unaligned beginning, if any.
374   for (; addr % kShadowCell && size; addr++, size--) {
375     int const kAccessSizeLog = 0;
376     Shadow cur(fast_state);
377     cur.SetWrite(is_write);
378     cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
379     MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
380         shadow_mem, cur);
381   }
382   if (unaligned)
383     shadow_mem += kShadowCnt;
384   // Handle middle part, if any.
385   for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) {
386     int const kAccessSizeLog = 3;
387     Shadow cur(fast_state);
388     cur.SetWrite(is_write);
389     cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
390     MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
391         shadow_mem, cur);
392     shadow_mem += kShadowCnt;
393   }
394   // Handle ending, if any.
395   for (; size; addr++, size--) {
396     int const kAccessSizeLog = 0;
397     Shadow cur(fast_state);
398     cur.SetWrite(is_write);
399     cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
400     MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
401         shadow_mem, cur);
402   }
403 }
404 
405 #if !SANITIZER_GO
406 void FiberSwitchImpl(ThreadState *from, ThreadState *to) {
407   Processor *proc = from->proc();
408   ProcUnwire(proc, from);
409   ProcWire(proc, to);
410   set_cur_thread(to);
411 }
412 
413 ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) {
414   void *mem = Alloc(sizeof(ThreadState));
415   ThreadState *fiber = static_cast<ThreadState *>(mem);
416   internal_memset(fiber, 0, sizeof(*fiber));
417   Tid tid = ThreadCreate(thr, pc, 0, true);
418   FiberSwitchImpl(thr, fiber);
419   ThreadStart(fiber, tid, 0, ThreadType::Fiber);
420   FiberSwitchImpl(fiber, thr);
421   return fiber;
422 }
423 
424 void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) {
425   FiberSwitchImpl(thr, fiber);
426   ThreadFinish(fiber);
427   FiberSwitchImpl(fiber, thr);
428   Free(fiber);
429 }
430 
431 void FiberSwitch(ThreadState *thr, uptr pc,
432                  ThreadState *fiber, unsigned flags) {
433   if (!(flags & FiberSwitchFlagNoSync))
434     Release(thr, pc, (uptr)fiber);
435   FiberSwitchImpl(thr, fiber);
436   if (!(flags & FiberSwitchFlagNoSync))
437     Acquire(fiber, pc, (uptr)fiber);
438 }
439 #endif
440 
441 }  // namespace __tsan
442