Commit Graph

20 Commits

Author SHA1 Message Date
Dmitry Vyukov d41233e9cf tsan: introduce kAccessFree
Add kAccessFree memory access flag (similar to kAccessVptr).
In preparation for MemoryAccess refactoring.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D107464
2021-08-04 18:03:41 +02:00
Dmitry Vyukov 831910c5c4 tsan: new MemoryAccess interface
Currently we have MemoryAccess function that accepts
"bool kAccessIsWrite, bool kIsAtomic" and 4 wrappers:
MemoryRead/MemoryWrite/MemoryReadAtomic/MemoryWriteAtomic.

Such scheme with bool flags is not particularly scalable/extendable.
Because of that we did not have Read/Write wrappers for UnalignedMemoryAccess,
and "true, false" or "false, true" at call sites is not very readable.

Moreover, the new tsan runtime will introduce more flags
(e.g. move "freed" and "vptr access" to memory acccess flags).
We can't have 16 wrappers and each flag also takes whole
64-bit register for non-inlined calls.

Introduce AccessType enum that contains bit mask of
read/write, atomic/non-atomic, and later free/non-free,
vptr/non-vptr.
Such scheme is more scalable, more readble, more efficient
(don't consume multiple registers for these flags during calls)
and allows to cover unaligned and range variations of memory
access functions as well.

Also switch from size log to just size.
The new tsan runtime won't have the limitation of supporting
only 1/2/4/8 access sizes, so we don't need the logarithms.

Also add an inline thunk that converts the new interface to the old one.
For inlined calls it should not add any overhead because
all flags/size can be computed as compile time.

Reviewed By: vitalybuka, melver

Differential Revision: https://reviews.llvm.org/D107276
2021-08-03 11:03:23 +02:00
Dmitry Vyukov 03372e72d3 tsan: remove unbalanced mutex unlock
The mutex is now unlocked by the scoped Lock object.

Differential Revision: https://reviews.llvm.org/D107266
2021-08-02 14:17:12 +02:00
Dmitry Vyukov 7bd81fe183 tsan: don't save creation stack for some sync objects
Currently we save the creation stack for sync objects always.
But it's not needed to some sync objects, most notably atomics.
We simply don't use atomic creation stack anywhere.
Allow callers to control saving of the creation stack
and don't save it for atomics.

Depends on D107257.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D107258
2021-08-02 13:30:24 +02:00
Dmitry Vyukov 9e3e97aa81 tsan: refactor MetaMap::GetAndLock interface
Don't lock the sync object inside of MetaMap methods.
This has several advantages:
 - the new interface does not confuse thread-safety analysis
   so we can remove a bunch of NO_THREAD_SAFETY_ANALYSIS attributes
 - this allows use of scoped lock objects
 - this allows more flexibility, e.g. locking some other mutex
   between searching and locking the sync object
Also prefix the methods with GetSync to be consistent with GetBlock method.
Also make interface wrappers inlinable, otherwise we either end up with
2 copies of the method, or with an additional call.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D107256
2021-08-02 13:29:46 +02:00
Dmitry Vyukov 103d075b05 tsan: introduce Tid and StackID typedefs
Currently we inconsistently use u32 and int for thread ids,
there are also "unique tid" and "os tid" and just lots of other
things identified by integers.
Additionally new tsan runtime will introduce yet another
thread identifier that is very different from current tids.
Similarly for stack IDs, it's easy to confuse u32 with other
integer identifiers. And when a function accepts u32 or a struct
contains u32 field, it's not always clear what it is.

Add Tid and StackID typedefs to make it clear what is what.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D107152
2021-07-31 09:05:31 +02:00
Dmitry Vyukov 0d68cfc996 tsan: store ThreadRegistry in Context by value
It's unclear why we allocate ThreadRegistry separately,
I assume it's some historical leftover.
Embed ThreadRegistry into Context.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D107045
2021-07-29 12:44:44 +02:00
Dmitry Vyukov 5acdfb7eda tsan: remove unused pc arguments
Remove pc argument of ThreadIgnoreEnd, ThreadIgnoreSyncEnd
and AcquireGlobal functions. It's unused and in some places
we don't even have a pc and pass 0 anyway.
Don't confuse readers and don't pretend that pc is needed
and that passing 0 is somehow deficient.

Use simpler convention for ThreadIgnoreBegin and ThreadIgnoreSyncBegin:
accept only pc instread of pc+save_stack. 0 pc means "don't save stack".

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D106973
2021-07-28 20:07:49 +02:00
Dmitry Vyukov 8924d8e37e tsan: disable thread safety analysis in more functions
In preparation for replacing tsan Mutex with sanitizer_common Mutex,
which has thread-safety annotations. Thread safety analysis does not
understand MetaMap::GetAndLock which returns a locked sync object.

Reviewed By: vitalybuka, melver

Differential Revision: https://reviews.llvm.org/D106548
2021-07-23 09:12:59 +02:00
Dmitry Vyukov adb55d7c32 tsan: remove the stats subsystem
I don't think the stat subsystem was ever used since tsan
development in 2012. But it adds lots of code and this
effectively dead code needs to be updated if the runtime
code changes, which adds maintanance cost for no benefit.
Normal profiler usually gives enough info and that info
is more trustworthy.
Remove the stats subsystem.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D106276
2021-07-20 07:47:38 +02:00
Dmitry Vyukov 92a3a2dc3e sanitizer_common: introduce kInvalidTid/kMainTid
Currently we have a bit of a mess related to tids:
 - sanitizers re-declare kInvalidTid multiple times
 - some call it kUnknownTid
 - implicit assumptions that main tid is 0
 - asan/memprof claim their tids need to fit into 24 bits,
   but this does not seem to be true anymore
 - inconsistent use of u32/int to store tids

Introduce kInvalidTid/kMainTid in sanitizer_common
and use them consistently.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D101428
2021-04-30 15:58:05 +02:00
Dmitry Vyukov ed7bf7d73f tsan: refactor fork handling
Commit efd254b636 ("tsan: fix deadlock in pthread_atfork callbacks")
fixed another deadlock related to atfork handling.
But builders with DCHECKs enabled reported failures of
pthread_atfork_deadlock2.c and pthread_atfork_deadlock3.c tests
related to the fact that we hold runtime locks on interceptor exit:
https://lab.llvm.org/buildbot/#/builders/70/builds/6727
This issue is somewhat inherent to the current approach,
we indeed execute user code (atfork callbacks) with runtime lock held.

Refactor fork handling to not run user code (atfork callbacks)
with runtime locks held. This change does this by installing
own atfork callbacks during runtime initialization.
Atfork callbacks run in LIFO order, so the expectation is that
our callbacks run last, right before the actual fork.
This way we lock runtime mutexes around fork, but not around
user callbacks.

Extend tests to also install after fork callbacks just to cover
more scenarios. Some tests also started reporting real races
that we previously suppressed.

Also extend tests to cover fork syscall support.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D101517
2021-04-30 08:48:20 +02:00
Tres Popp d1e08b124c Revert "tsan: refactor fork handling"
This reverts commit e1021dd1fd.
2021-04-28 14:08:33 +02:00
Dmitry Vyukov e1021dd1fd tsan: refactor fork handling
Commit efd254b636 ("tsan: fix deadlock in pthread_atfork callbacks")
fixed another deadlock related to atfork handling.
But builders with DCHECKs enabled reported failures of
pthread_atfork_deadlock2.c and pthread_atfork_deadlock3.c tests
related to the fact that we hold runtime locks on interceptor exit:
https://lab.llvm.org/buildbot/#/builders/70/builds/6727
This issue is somewhat inherent to the current approach,
we indeed execute user code (atfork callbacks) with runtime lock held.

Refactor fork handling to not run user code (atfork callbacks)
with runtime locks held. This change does this by installing
own atfork callbacks during runtime initialization.
Atfork callbacks run in LIFO order, so the expectation is that
our callbacks run last, right before the actual fork.
This way we lock runtime mutexes around fork, but not around
user callbacks.

Extend tests to also install after fork callbacks just to cover
more scenarios. Some tests also started reporting real races
that we previously suppressed.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D101385
2021-04-27 22:37:27 +02:00
Evgenii Stepanov 5275d772da Revert "tsan: fix deadlock in pthread_atfork callbacks"
Tests fail on debug builders. See the forward fix in
https://reviews.llvm.org/D101385.

This reverts commit efd254b636.
2021-04-27 12:36:31 -07:00
Dmitry Vyukov efd254b636 tsan: fix deadlock in pthread_atfork callbacks
We take report/thread_registry locks around fork.
This means we cannot report any bugs in atfork handlers.
We resolved this by enabling per-thread ignores around fork.
This resolved some of the cases, but not all.
The added test triggers a race report from a signal handler
called from atfork callback, we reset per-thread ignores
around signal handlers, so we tried to report it and deadlocked.
But there are more cases: a signal handler can be called
synchronously if it's sent to itself. Or any other report
types would cause deadlocks as well: mutex misuse,
signal handler spoiling errno, etc.
Disable all reports for the duration of fork with
thr->suppress_reports and don't re-enable them around
signal handlers.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D101154
2021-04-27 13:25:26 +02:00
Vitaly Buka d48f2d7c02 [sanitizer] Cleanup -Wnon-virtual-dtor warnings 2020-11-02 20:30:50 -08:00
Dmitry Vyukov 4408eeed0f tsan: fix false positives in AcquireGlobal
Add ThreadClock:: global_acquire_ which is the last time another thread
has done a global acquire of this thread's clock.

It helps to avoid problem described in:
https://github.com/golang/go/issues/39186
See test/tsan/java_finalizer2.cpp for a regression test.
Note the failuire is _extremely_ hard to hit, so if you are trying
to reproduce it, you may want to run something like:
$ go get golang.org/x/tools/cmd/stress
$ stress -p=64 ./a.out

The crux of the problem is roughly as follows.
A number of O(1) optimizations in the clocks algorithm assume proper
transitive cumulative propagation of clock values. The AcquireGlobal
operation may produce an inconsistent non-linearazable view of
thread clocks. Namely, it may acquire a later value from a thread
with a higher ID, but fail to acquire an earlier value from a thread
with a lower ID. If a thread that executed AcquireGlobal then releases
to a sync clock, it will spoil the sync clock with the inconsistent
values. If another thread later releases to the sync clock, the optimized
algorithm may break.

The exact sequence of events that leads to the failure.
- thread 1 executes AcquireGlobal
- thread 1 acquires value 1 for thread 2
- thread 2 increments clock to 2
- thread 2 releases to sync object 1
- thread 3 at time 1
- thread 3 acquires from sync object 1
- thread 1 acquires value 1 for thread 3
- thread 1 releases to sync object 2
- sync object 2 clock has 1 for thread 2 and 1 for thread 3
- thread 3 releases to sync object 2
- thread 3 sees value 1 in the clock for itself
  and decides that it has already released to the clock
  and did not acquire anything from other threads after that
  (the last_acquire_ check in release operation)
- thread 3 does not update the value for thread 2 in the clock from 1 to 2
- thread 4 acquires from sync object 2
- thread 4 detects a false race with thread 2
  as it should have been synchronized with thread 2 up to time 2,
  but because of the broken clock it is now synchronized only up to time 1

The global_acquire_ value helps to prevent this scenario.
Namely, thread 3 will not trust any own clock values up to global_acquire_
for the purposes of the last_acquire_ optimization.

Reviewed-in: https://reviews.llvm.org/D80474
Reported-by: nvanbenschoten (Nathan VanBenschoten)
2020-05-27 16:27:47 +02:00
Dmitry Vyukov 180d211770 tsan: Adding releaseAcquire() to ThreadClock
realeaseAcquire() is a new function added to TSan in support of the Go data-race detector.
It's semantics is:

void ThreadClock::releaseAcquire(SyncClock *sc) const {
  for (int i = 0; i < kMaxThreads; i++) {
    tmp = clock[i];
    clock[i] = max(clock[i], sc->clock[i]);
    sc->clock[i] = tmp;
  }
}

For context see: https://go-review.googlesource.com/c/go/+/220419

Reviewed-in: https://reviews.llvm.org/D76322
Author: dfava (Daniel Fava)
2020-03-24 11:27:46 +01:00
Nico Weber 5a3bb1a4d6 compiler-rt: Rename .cc file in lib/tsan/rtl to .cpp
Like r367463, but for tsan/rtl.

llvm-svn: 367564
2019-08-01 14:22:42 +00:00