1 //===-- tsan_rtl.cpp ------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
11 // Main file (entry points) for the TSan run-time.
12 //===----------------------------------------------------------------------===//
16 #include "sanitizer_common/sanitizer_atomic.h"
17 #include "sanitizer_common/sanitizer_common.h"
18 #include "sanitizer_common/sanitizer_file.h"
19 #include "sanitizer_common/sanitizer_libc.h"
20 #include "sanitizer_common/sanitizer_placement_new.h"
21 #include "sanitizer_common/sanitizer_stackdepot.h"
22 #include "sanitizer_common/sanitizer_symbolizer.h"
23 #include "tsan_defs.h"
24 #include "tsan_interface.h"
25 #include "tsan_mman.h"
26 #include "tsan_platform.h"
27 #include "tsan_suppressions.h"
28 #include "tsan_symbolize.h"
29 #include "ubsan/ubsan_init.h"
31 volatile int __tsan_resumed
= 0;
33 extern "C" void __tsan_resume() {
40 void (*on_initialize
)(void);
41 int (*on_finalize
)(int);
44 #if !SANITIZER_GO && !SANITIZER_MAC
45 __attribute__((tls_model("initial-exec")))
46 THREADLOCAL
char cur_thread_placeholder
[sizeof(ThreadState
)] ALIGNED(
47 SANITIZER_CACHE_LINE_SIZE
);
49 static char ctx_placeholder
[sizeof(Context
)] ALIGNED(SANITIZER_CACHE_LINE_SIZE
);
52 // Can be overriden by a front-end.
53 #ifdef TSAN_EXTERNAL_HOOKS
54 bool OnFinalize(bool failed
);
58 SANITIZER_WEAK_CXX_DEFAULT_IMPL
59 bool OnFinalize(bool failed
) {
62 return on_finalize(failed
);
66 SANITIZER_WEAK_CXX_DEFAULT_IMPL
75 static ThreadContextBase
*CreateThreadContext(Tid tid
) {
76 // Map thread trace when context is created.
78 internal_snprintf(name
, sizeof(name
), "trace %u", tid
);
79 MapThreadTrace(GetThreadTrace(tid
), TraceSize() * sizeof(Event
), name
);
80 const uptr hdr
= GetThreadTraceHeader(tid
);
81 internal_snprintf(name
, sizeof(name
), "trace header %u", tid
);
82 MapThreadTrace(hdr
, sizeof(Trace
), name
);
83 new((void*)hdr
) Trace();
84 // We are going to use only a small part of the trace with the default
85 // value of history_size. However, the constructor writes to the whole trace.
86 // Release the unused part.
87 uptr hdr_end
= hdr
+ sizeof(Trace
);
88 hdr_end
-= sizeof(TraceHeader
) * (kTraceParts
- TraceParts());
89 hdr_end
= RoundUp(hdr_end
, GetPageSizeCached());
90 if (hdr_end
< hdr
+ sizeof(Trace
)) {
91 ReleaseMemoryPagesToOS(hdr_end
, hdr
+ sizeof(Trace
));
92 uptr unused
= hdr
+ sizeof(Trace
) - hdr_end
;
93 if (hdr_end
!= (uptr
)MmapFixedNoAccess(hdr_end
, unused
)) {
94 Report("ThreadSanitizer: failed to mprotect [0x%zx-0x%zx) \n", hdr_end
,
96 CHECK("unable to mprotect" && 0);
99 return New
<ThreadContext
>(tid
);
103 static const u32 kThreadQuarantineSize
= 16;
105 static const u32 kThreadQuarantineSize
= 64;
110 report_mtx(MutexTypeReport
),
112 thread_registry(CreateThreadContext
, kMaxTid
, kThreadQuarantineSize
,
114 racy_mtx(MutexTypeRacy
),
117 fired_suppressions_mtx(MutexTypeFired
),
118 clock_alloc(LINKER_INITIALIZED
, "clock allocator") {
119 fired_suppressions
.reserve(8);
122 // The objects are allocated in TLS, so one may rely on zero-initialization.
123 ThreadState::ThreadState(Context
*ctx
, Tid tid
, int unique_id
, u64 epoch
,
124 unsigned reuse_count
, uptr stk_addr
, uptr stk_size
,
125 uptr tls_addr
, uptr tls_size
)
126 : fast_state(tid
, epoch
)
127 // Do not touch these, rely on zero initialization,
128 // they may be accessed before the ctor.
129 // , ignore_reads_and_writes()
130 // , ignore_interceptors()
132 clock(tid
, reuse_count
)
139 unique_id(unique_id
),
146 last_sleep_clock(tid
)
149 CHECK_EQ(reinterpret_cast<uptr
>(this) % SANITIZER_CACHE_LINE_SIZE
, 0);
151 shadow_stack_pos
= shadow_stack
;
152 shadow_stack_end
= shadow_stack
+ kShadowStackSize
;
154 // Setup dynamic shadow stack.
155 const int kInitStackSize
= 8;
156 shadow_stack
= (uptr
*)Alloc(kInitStackSize
* sizeof(uptr
));
157 shadow_stack_pos
= shadow_stack
;
158 shadow_stack_end
= shadow_stack
+ kInitStackSize
;
163 void MemoryProfiler(u64 uptime
) {
164 if (ctx
->memprof_fd
== kInvalidFd
)
166 InternalMmapVector
<char> buf(4096);
167 WriteMemoryProfile(buf
.data(), buf
.size(), uptime
);
168 WriteToFile(ctx
->memprof_fd
, buf
.data(), internal_strlen(buf
.data()));
171 void InitializeMemoryProfiler() {
172 ctx
->memprof_fd
= kInvalidFd
;
173 const char *fname
= flags()->profile_memory
;
174 if (!fname
|| !fname
[0])
176 if (internal_strcmp(fname
, "stdout") == 0) {
178 } else if (internal_strcmp(fname
, "stderr") == 0) {
181 InternalScopedString filename
;
182 filename
.append("%s.%d", fname
, (int)internal_getpid());
183 ctx
->memprof_fd
= OpenFile(filename
.data(), WrOnly
);
184 if (ctx
->memprof_fd
== kInvalidFd
) {
185 Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
191 MaybeSpawnBackgroundThread();
194 static void *BackgroundThread(void *arg
) {
195 // This is a non-initialized non-user thread, nothing to see here.
196 // We don't use ScopedIgnoreInterceptors, because we want ignores to be
197 // enabled even when the thread function exits (e.g. during pthread thread
199 cur_thread_init()->ignore_interceptors
++;
200 const u64 kMs2Ns
= 1000 * 1000;
201 const u64 start
= NanoTime();
203 u64 last_flush
= NanoTime();
206 atomic_load(&ctx
->stop_background_thread
, memory_order_relaxed
) == 0;
209 u64 now
= NanoTime();
211 // Flush memory if requested.
212 if (flags()->flush_memory_ms
> 0) {
213 if (last_flush
+ flags()->flush_memory_ms
* kMs2Ns
< now
) {
214 VPrintf(1, "ThreadSanitizer: periodic memory flush\n");
216 last_flush
= NanoTime();
219 if (flags()->memory_limit_mb
> 0) {
221 uptr limit
= uptr(flags()->memory_limit_mb
) << 20;
222 VPrintf(1, "ThreadSanitizer: memory flush check"
223 " RSS=%llu LAST=%llu LIMIT=%llu\n",
224 (u64
)rss
>> 20, (u64
)last_rss
>> 20, (u64
)limit
>> 20);
225 if (2 * rss
> limit
+ last_rss
) {
226 VPrintf(1, "ThreadSanitizer: flushing memory due to RSS\n");
229 VPrintf(1, "ThreadSanitizer: memory flushed RSS=%llu\n", (u64
)rss
>>20);
234 MemoryProfiler(now
- start
);
236 // Flush symbolizer cache if requested.
237 if (flags()->flush_symbolizer_ms
> 0) {
238 u64 last
= atomic_load(&ctx
->last_symbolize_time_ns
,
239 memory_order_relaxed
);
240 if (last
!= 0 && last
+ flags()->flush_symbolizer_ms
* kMs2Ns
< now
) {
241 Lock
l(&ctx
->report_mtx
);
242 ScopedErrorReportLock l2
;
244 atomic_store(&ctx
->last_symbolize_time_ns
, 0, memory_order_relaxed
);
251 static void StartBackgroundThread() {
252 ctx
->background_thread
= internal_start_thread(&BackgroundThread
, 0);
256 static void StopBackgroundThread() {
257 atomic_store(&ctx
->stop_background_thread
, 1, memory_order_relaxed
);
258 internal_join_thread(ctx
->background_thread
);
259 ctx
->background_thread
= 0;
264 void DontNeedShadowFor(uptr addr
, uptr size
) {
265 ReleaseMemoryPagesToOS(reinterpret_cast<uptr
>(MemToShadow(addr
)),
266 reinterpret_cast<uptr
>(MemToShadow(addr
+ size
)));
270 void UnmapShadow(ThreadState
*thr
, uptr addr
, uptr size
) {
271 if (size
== 0) return;
272 DontNeedShadowFor(addr
, size
);
273 ScopedGlobalProcessor sgp
;
274 ctx
->metamap
.ResetRange(thr
->proc(), addr
, size
);
278 void MapShadow(uptr addr
, uptr size
) {
279 // Global data is not 64K aligned, but there are no adjacent mappings,
280 // so we can get away with unaligned mapping.
281 // CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
282 const uptr kPageSize
= GetPageSizeCached();
283 uptr shadow_begin
= RoundDownTo((uptr
)MemToShadow(addr
), kPageSize
);
284 uptr shadow_end
= RoundUpTo((uptr
)MemToShadow(addr
+ size
), kPageSize
);
285 if (!MmapFixedSuperNoReserve(shadow_begin
, shadow_end
- shadow_begin
,
289 // Meta shadow is 2:1, so tread carefully.
290 static bool data_mapped
= false;
291 static uptr mapped_meta_end
= 0;
292 uptr meta_begin
= (uptr
)MemToMeta(addr
);
293 uptr meta_end
= (uptr
)MemToMeta(addr
+ size
);
294 meta_begin
= RoundDownTo(meta_begin
, 64 << 10);
295 meta_end
= RoundUpTo(meta_end
, 64 << 10);
297 // First call maps data+bss.
299 if (!MmapFixedSuperNoReserve(meta_begin
, meta_end
- meta_begin
,
303 // Mapping continuous heap.
304 // Windows wants 64K alignment.
305 meta_begin
= RoundDownTo(meta_begin
, 64 << 10);
306 meta_end
= RoundUpTo(meta_end
, 64 << 10);
307 if (meta_end
<= mapped_meta_end
)
309 if (meta_begin
< mapped_meta_end
)
310 meta_begin
= mapped_meta_end
;
311 if (!MmapFixedSuperNoReserve(meta_begin
, meta_end
- meta_begin
,
314 mapped_meta_end
= meta_end
;
316 VPrintf(2, "mapped meta shadow for (0x%zx-0x%zx) at (0x%zx-0x%zx)\n", addr
,
317 addr
+ size
, meta_begin
, meta_end
);
320 void MapThreadTrace(uptr addr
, uptr size
, const char *name
) {
321 DPrintf("#0: Mapping trace at 0x%zx-0x%zx(0x%zx)\n", addr
, addr
+ size
, size
);
322 CHECK_GE(addr
, TraceMemBeg());
323 CHECK_LE(addr
+ size
, TraceMemEnd());
324 CHECK_EQ(addr
, addr
& ~((64 << 10) - 1)); // windows wants 64K alignment
325 if (!MmapFixedSuperNoReserve(addr
, size
, name
)) {
326 Printf("FATAL: ThreadSanitizer can not mmap thread trace (0x%zx/0x%zx)\n",
333 static void OnStackUnwind(const SignalContext
&sig
, const void *,
334 BufferedStackTrace
*stack
) {
335 stack
->Unwind(StackTrace::GetNextInstructionPc(sig
.pc
), sig
.bp
, sig
.context
,
336 common_flags()->fast_unwind_on_fatal
);
339 static void TsanOnDeadlySignal(int signo
, void *siginfo
, void *context
) {
340 HandleDeadlySignal(siginfo
, context
, GetTid(), &OnStackUnwind
, nullptr);
345 // There is high probability that interceptors will check-fail as well,
346 // on the other hand there is no sense in processing interceptors
347 // since we are going to die soon.
348 ScopedIgnoreInterceptors ignore
;
350 cur_thread()->ignore_sync
++;
351 cur_thread()->ignore_reads_and_writes
++;
353 PrintCurrentStackSlow(StackTrace::GetCurrentPc());
358 void Initialize(ThreadState
*thr
) {
359 // Thread safe because done before all threads exist.
362 is_initialized
= true;
363 // We are not ready to handle interceptors yet.
364 ScopedIgnoreInterceptors ignore
;
365 SanitizerToolName
= "ThreadSanitizer";
366 // Install tool-specific callbacks in sanitizer_common.
367 SetCheckUnwindCallback(CheckUnwind
);
369 ctx
= new(ctx_placeholder
) Context
;
370 const char *env_name
= SANITIZER_GO
? "GORACE" : "TSAN_OPTIONS";
371 const char *options
= GetEnv(env_name
);
374 InitializeFlags(&ctx
->flags
, options
, env_name
);
375 AvoidCVE_2016_2143();
376 __sanitizer::InitializePlatformEarly();
377 __tsan::InitializePlatformEarly();
380 // Re-exec ourselves if we need to set additional env or command line args.
383 InitializeAllocator();
384 ReplaceSystemMalloc();
386 if (common_flags()->detect_deadlocks
)
387 ctx
->dd
= DDetector::Create(flags());
388 Processor
*proc
= ProcCreate();
390 InitializeInterceptors();
391 InitializePlatform();
392 InitializeDynamicAnnotations();
394 InitializeShadowMemory();
395 InitializeAllocatorLate();
396 InstallDeadlySignalHandlers(TsanOnDeadlySignal
);
398 // Setup correct file descriptor for error reports.
399 __sanitizer_set_report_path(common_flags()->log_path
);
400 InitializeSuppressions();
402 InitializeLibIgnore();
403 Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer
, ExitSymbolizer
);
406 VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n",
407 (int)internal_getpid());
409 // Initialize thread 0.
410 Tid tid
= ThreadCreate(thr
, 0, 0, true);
411 CHECK_EQ(tid
, kMainTid
);
412 ThreadStart(thr
, tid
, GetTid(), ThreadType::Regular
);
413 #if TSAN_CONTAINS_UBSAN
414 __ubsan::InitAsPlugin();
416 ctx
->initialized
= true;
419 Symbolizer::LateInitialize();
420 InitializeMemoryProfiler();
423 if (flags()->stop_on_start
) {
424 Printf("ThreadSanitizer is suspended at startup (pid %d)."
425 " Call __tsan_resume().\n",
426 (int)internal_getpid());
427 while (__tsan_resumed
== 0) {}
433 void MaybeSpawnBackgroundThread() {
434 // On MIPS, TSan initialization is run before
435 // __pthread_initialize_minimal_internal() is finished, so we can not spawn
437 #if !SANITIZER_GO && !defined(__mips__)
438 static atomic_uint32_t bg_thread
= {};
439 if (atomic_load(&bg_thread
, memory_order_relaxed
) == 0 &&
440 atomic_exchange(&bg_thread
, 1, memory_order_relaxed
) == 0) {
441 StartBackgroundThread();
442 SetSandboxingCallback(StopBackgroundThread
);
448 int Finalize(ThreadState
*thr
) {
451 if (common_flags()->print_module_map
== 1)
454 if (flags()->atexit_sleep_ms
> 0 && ThreadCount(thr
) > 1)
455 SleepForMillis(flags()->atexit_sleep_ms
);
457 // Wait for pending reports.
458 ctx
->report_mtx
.Lock();
459 { ScopedErrorReportLock l
; }
460 ctx
->report_mtx
.Unlock();
463 if (Verbosity()) AllocatorPrintStats();
468 if (ctx
->nreported
) {
471 Printf("ThreadSanitizer: reported %d warnings\n", ctx
->nreported
);
473 Printf("Found %d data race(s)\n", ctx
->nreported
);
477 if (common_flags()->print_suppressions
)
478 PrintMatchedSuppressions();
480 failed
= OnFinalize(failed
);
482 return failed
? common_flags()->exitcode
: 0;
486 void ForkBefore(ThreadState
*thr
, uptr pc
) NO_THREAD_SAFETY_ANALYSIS
{
487 ctx
->thread_registry
.Lock();
488 ctx
->report_mtx
.Lock();
489 ScopedErrorReportLock::Lock();
490 // Suppress all reports in the pthread_atfork callbacks.
491 // Reports will deadlock on the report_mtx.
492 // We could ignore sync operations as well,
493 // but so far it's unclear if it will do more good or harm.
494 // Unnecessarily ignoring things can lead to false positives later.
495 thr
->suppress_reports
++;
496 // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
497 // we'll assert in CheckNoLocks() unless we ignore interceptors.
498 thr
->ignore_interceptors
++;
501 void ForkParentAfter(ThreadState
*thr
, uptr pc
) NO_THREAD_SAFETY_ANALYSIS
{
502 thr
->suppress_reports
--; // Enabled in ForkBefore.
503 thr
->ignore_interceptors
--;
504 ScopedErrorReportLock::Unlock();
505 ctx
->report_mtx
.Unlock();
506 ctx
->thread_registry
.Unlock();
509 void ForkChildAfter(ThreadState
*thr
, uptr pc
,
510 bool start_thread
) NO_THREAD_SAFETY_ANALYSIS
{
511 thr
->suppress_reports
--; // Enabled in ForkBefore.
512 thr
->ignore_interceptors
--;
513 ScopedErrorReportLock::Unlock();
514 ctx
->report_mtx
.Unlock();
515 ctx
->thread_registry
.Unlock();
518 ctx
->thread_registry
.GetNumberOfThreads(0, 0, &nthread
/* alive threads */);
519 VPrintf(1, "ThreadSanitizer: forked new process with pid %d,"
520 " parent had %d threads\n", (int)internal_getpid(), (int)nthread
);
523 StartBackgroundThread();
525 // We've just forked a multi-threaded process. We cannot reasonably function
526 // after that (some mutexes may be locked before fork). So just enable
527 // ignores for everything in the hope that we will exec soon.
528 ctx
->after_multithreaded_fork
= true;
529 thr
->ignore_interceptors
++;
530 ThreadIgnoreBegin(thr
, pc
);
531 ThreadIgnoreSyncBegin(thr
, pc
);
538 void GrowShadowStack(ThreadState
*thr
) {
539 const int sz
= thr
->shadow_stack_end
- thr
->shadow_stack
;
540 const int newsz
= 2 * sz
;
541 auto *newstack
= (uptr
*)Alloc(newsz
* sizeof(uptr
));
542 internal_memcpy(newstack
, thr
->shadow_stack
, sz
* sizeof(uptr
));
543 Free(thr
->shadow_stack
);
544 thr
->shadow_stack
= newstack
;
545 thr
->shadow_stack_pos
= newstack
+ sz
;
546 thr
->shadow_stack_end
= newstack
+ newsz
;
550 StackID
CurrentStackId(ThreadState
*thr
, uptr pc
) {
551 if (!thr
->is_inited
) // May happen during bootstrap.
552 return kInvalidStackID
;
555 DCHECK_LT(thr
->shadow_stack_pos
, thr
->shadow_stack_end
);
557 if (thr
->shadow_stack_pos
== thr
->shadow_stack_end
)
558 GrowShadowStack(thr
);
560 thr
->shadow_stack_pos
[0] = pc
;
561 thr
->shadow_stack_pos
++;
563 StackID id
= StackDepotPut(
564 StackTrace(thr
->shadow_stack
, thr
->shadow_stack_pos
- thr
->shadow_stack
));
566 thr
->shadow_stack_pos
--;
573 void TraceSwitchPart(ThreadState
*thr
) {
574 Trace
*trace
= &thr
->tctx
->trace
;
575 Event
*pos
= reinterpret_cast<Event
*>(atomic_load_relaxed(&thr
->trace_pos
));
576 DCHECK_EQ(reinterpret_cast<uptr
>(pos
+ 1) & TracePart::kAlignment
, 0);
577 auto *part
= trace
->parts
.Back();
578 DPrintf("TraceSwitchPart part=%p pos=%p\n", part
, pos
);
580 // We can get here when we still have space in the current trace part.
581 // The fast-path check in TraceAcquire has false positives in the middle of
582 // the part. Check if we are indeed at the end of the current part or not,
583 // and fill any gaps with NopEvent's.
584 Event
*end
= &part
->events
[TracePart::kSize
];
585 DCHECK_GE(pos
, &part
->events
[0]);
588 if ((reinterpret_cast<uptr
>(pos
) & TracePart::kAlignment
) ==
589 TracePart::kAlignment
)
592 DCHECK_LE(pos
+ 2, end
);
593 atomic_store_relaxed(&thr
->trace_pos
, reinterpret_cast<uptr
>(pos
));
594 // Ensure we setup trace so that the next TraceAcquire
595 // won't detect trace part end.
597 CHECK(TraceAcquire(thr
, &ev
));
600 // We are indeed at the end.
601 for (; pos
< end
; pos
++) *pos
= NopEvent
;
604 if (ctx
->after_multithreaded_fork
) {
605 // We just need to survive till exec.
607 atomic_store_relaxed(&thr
->trace_pos
,
608 reinterpret_cast<uptr
>(&part
->events
[0]));
612 part
= new (MmapOrDie(sizeof(TracePart
), "TracePart")) TracePart();
614 thr
->trace_prev_pc
= 0;
616 Lock
lock(&trace
->mtx
);
617 trace
->parts
.PushBack(part
);
618 atomic_store_relaxed(&thr
->trace_pos
,
619 reinterpret_cast<uptr
>(&part
->events
[0]));
621 // Make this part self-sufficient by restoring the current stack
622 // and mutex set in the beginning of the trace.
624 for (uptr
*pos
= &thr
->shadow_stack
[0]; pos
< thr
->shadow_stack_pos
; pos
++)
625 CHECK(TryTraceFunc(thr
, *pos
));
626 for (uptr i
= 0; i
< thr
->mset
.Size(); i
++) {
627 MutexSet::Desc d
= thr
->mset
.Get(i
);
628 TraceMutexLock(thr
, d
.write
? EventType::kLock
: EventType::kRLock
, 0,
635 void TraceSwitch(ThreadState
*thr
) {
637 if (ctx
->after_multithreaded_fork
)
641 Trace
*thr_trace
= ThreadTrace(thr
->tid
);
642 Lock
l(&thr_trace
->mtx
);
643 unsigned trace
= (thr
->fast_state
.epoch() / kTracePartSize
) % TraceParts();
644 TraceHeader
*hdr
= &thr_trace
->headers
[trace
];
645 hdr
->epoch0
= thr
->fast_state
.epoch();
646 ObtainCurrentStack(thr
, 0, &hdr
->stack0
);
647 hdr
->mset0
= thr
->mset
;
651 Trace
*ThreadTrace(Tid tid
) { return (Trace
*)GetThreadTraceHeader(tid
); }
653 uptr
TraceTopPC(ThreadState
*thr
) {
654 Event
*events
= (Event
*)GetThreadTrace(thr
->tid
);
655 uptr pc
= events
[thr
->fast_state
.GetTracePos()];
660 return (uptr
)(1ull << (kTracePartSizeBits
+ flags()->history_size
+ 1));
664 return TraceSize() / kTracePartSize
;
668 extern "C" void __tsan_trace_switch() {
669 TraceSwitch(cur_thread());
672 extern "C" void __tsan_report_race() {
673 ReportRace(cur_thread());
677 void ThreadIgnoreBegin(ThreadState
*thr
, uptr pc
) {
678 DPrintf("#%d: ThreadIgnoreBegin\n", thr
->tid
);
679 thr
->ignore_reads_and_writes
++;
680 CHECK_GT(thr
->ignore_reads_and_writes
, 0);
681 thr
->fast_state
.SetIgnoreBit();
683 if (pc
&& !ctx
->after_multithreaded_fork
)
684 thr
->mop_ignore_set
.Add(CurrentStackId(thr
, pc
));
688 void ThreadIgnoreEnd(ThreadState
*thr
) {
689 DPrintf("#%d: ThreadIgnoreEnd\n", thr
->tid
);
690 CHECK_GT(thr
->ignore_reads_and_writes
, 0);
691 thr
->ignore_reads_and_writes
--;
692 if (thr
->ignore_reads_and_writes
== 0) {
693 thr
->fast_state
.ClearIgnoreBit();
695 thr
->mop_ignore_set
.Reset();
701 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
702 uptr
__tsan_testonly_shadow_stack_current_size() {
703 ThreadState
*thr
= cur_thread();
704 return thr
->shadow_stack_pos
- thr
->shadow_stack
;
708 void ThreadIgnoreSyncBegin(ThreadState
*thr
, uptr pc
) {
709 DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr
->tid
);
711 CHECK_GT(thr
->ignore_sync
, 0);
713 if (pc
&& !ctx
->after_multithreaded_fork
)
714 thr
->sync_ignore_set
.Add(CurrentStackId(thr
, pc
));
718 void ThreadIgnoreSyncEnd(ThreadState
*thr
) {
719 DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr
->tid
);
720 CHECK_GT(thr
->ignore_sync
, 0);
723 if (thr
->ignore_sync
== 0)
724 thr
->sync_ignore_set
.Reset();
728 bool MD5Hash::operator==(const MD5Hash
&other
) const {
729 return hash
[0] == other
.hash
[0] && hash
[1] == other
.hash
[1];
733 void build_consistency_debug() {}
735 void build_consistency_release() {}
738 } // namespace __tsan
740 #if SANITIZER_CHECK_DEADLOCKS
741 namespace __sanitizer
{
742 using namespace __tsan
;
743 MutexMeta mutex_meta
[] = {
744 {MutexInvalid
, "Invalid", {}},
745 {MutexThreadRegistry
, "ThreadRegistry", {}},
746 {MutexTypeTrace
, "Trace", {MutexLeaf
}},
747 {MutexTypeReport
, "Report", {MutexTypeSyncVar
}},
748 {MutexTypeSyncVar
, "SyncVar", {}},
749 {MutexTypeAnnotations
, "Annotations", {}},
750 {MutexTypeAtExit
, "AtExit", {MutexTypeSyncVar
}},
751 {MutexTypeFired
, "Fired", {MutexLeaf
}},
752 {MutexTypeRacy
, "Racy", {MutexLeaf
}},
753 {MutexTypeGlobalProc
, "GlobalProc", {}},
757 void PrintMutexPC(uptr pc
) { StackTrace(&pc
, 1).Print(); }
758 } // namespace __sanitizer