This is an archive of the discontinued LLVM Phabricator instance.

tsan: switch to the new sanitizer_common mutex
ClosedPublic

Authored by dvyukov on Jul 20 2021, 10:08 AM.

Details

Summary

Now that sanitizer_common mutex has feature-parity with tsan mutex,
switch tsan to the sanitizer_common mutex and remove tsan's custom mutex.

Diff Detail

Event Timeline

dvyukov created this revision.Jul 20 2021, 10:08 AM
dvyukov requested review of this revision.Jul 20 2021, 10:08 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 20 2021, 10:08 AM
Herald added a subscriber: Restricted Project. · View Herald Transcript

"arc patch D106379" conflicts with origin/main

dvyukov updated this revision to Diff 360203.Jul 20 2021, 10:39 AM

upload all 3 commits

This review contains 3 commits. I figured out that just the sanitizer_common part w/o a use example is not very useful for review, so added how tsan uses it as well.
I think Phabricator does not allow to review commit-per-commit, at least I did not find how to do it. So I uploaded this to github as well:
https://github.com/dvyukov/llvm-project/pull/5/commits

vitalybuka added a comment.EditedJul 20 2021, 10:42 AM

This review contains 3 commits. I figured out that just the sanitizer_common part w/o a use example is not very useful for review, so added how tsan uses it as well.
I think Phabricator does not allow to review commit-per-commit, at least I did not find how to do it. So I uploaded this to github as well:
https://github.com/dvyukov/llvm-project/pull/5/commits

Can you just set entire "parent/child" chain in Phabricator?

I have more and more doubts re the thread safety annotations over time. They were kinda useful in a single particular case in new tsan runtime, where static analysis pointed precisely at unprotected accesses. But now we need more and more of NO_THREAD_SAFETY_ANALYSIS... maybe we should drop it?

"arc patch D106379" conflicts with origin/main

I hope this is fixed after I pushed all 3 commits.

Can you just set entire "parent/child" chain in Phabricator?

Where/how do I do this?

vitalybuka added a comment.EditedJul 20 2021, 10:53 AM

"arc patch D106379" conflicts with origin/main

I hope this is fixed after I pushed all 3 commits.

Can you just set entire "parent/child" chain in Phabricator?

Where/how do I do this?

"Edit Related Revisions..." on the right menu of Phabricator. and check "Revision Contents" > Stack
I already linked D106350
"rename test Mutex to UserMutex" needs to be in there as well

vitalybuka added a comment.EditedJul 20 2021, 10:56 AM

"arc patch D106379" conflicts with origin/main

I hope this is fixed after I pushed all 3 commits.

Can you just set entire "parent/child" chain in Phabricator?

Where/how do I do this?

"Edit Related Revisions..." on the right menu of Phabricator. and check "Revision Contents" > Stack
I already linked D106350
"rename test Mutex to UserMutex" needs to be in there as well

D106379+D106350 do not conflict, but without "rename" patch i am not sure if it's in valid state.

"arc patch D106379" conflicts with origin/main

I hope this is fixed after I pushed all 3 commits.

Can you just set entire "parent/child" chain in Phabricator?

Where/how do I do this?

"Edit Related Revisions..." on the right menu of Phabricator. and check "Revision Contents" > Stack
I already linked D106350
"rename test Mutex to UserMutex" needs to be in there as well

D106379+D106350 do not conflict, but without "rename" patch i am not sure if it's in valid state.

This change is self-contained and applies on top of a recent main/HEAD:

$ git log --oneline
5d29184bb9bb (HEAD -> mutex-deadlock-detector) tsan: switch to the new sanitizer_common mutex
44e53dcd902c tsan: rename test Mutex to UserMutex
9d223a2c38f0 sanitizer_common: add deadlock detection to the Mutex2
15af3aaa2e8a (origin/main, main) [AArch64][SME] Add system registers and related instructions

vitalybuka added inline comments.Jul 20 2021, 11:05 PM
compiler-rt/lib/sanitizer_common/sanitizer_mutex.cpp
46 ↗(On Diff #360203)

please add "static" here and below where appropriate

58 ↗(On Diff #360203)

I guess "= {}" can insert interceptable memset

66 ↗(On Diff #360203)

uptr and now (int) cast?

99 ↗(On Diff #360203)

this could be nicely calculated with bit operations on stack with
u32 trans[kMutexTypeMax];

first we convert to:

u32 trans[kMutexTypeMax] = {};
  for (int i = 0; i < mutex_count; i++) {
    for (int j = 0; j < mutex_count; j++) 
      if (mutex_can_lock[i][j])
        trans[i] |= 1 << j;
  }
  for (int k = 0; k < mutex_count; k++) {
    for (int i = 0; i < mutex_count; i++) {
      if (trans[i] & (1 << k))
        # set bit j in trans[i] for each bit j in trans[k]
        for (int j = 0; j < mutex_count; j++) {
          if (trans[k] & (1 << j))
            trans[i] |= (1 << j);
        }
    }
  }

so

for (int k = 0; k < mutex_count; k++) {
    for (int i = 0; i < mutex_count; i++) {
      if (trans[i] & (1 << k))
        trans[i] |= trans[k];
    }
  }

but I didn't compile :)

198 ↗(On Diff #360203)

to my taste CheckedMutex can be separated from "tsan: switch to the new sanitizer_common mutex"

compiler-rt/lib/sanitizer_common/sanitizer_mutex.h
152

What is the purpose of this inheritance?
Usually composition is recommended in cases like this, e.g. https://google.github.io/styleguide/cppguide.html#Inheritance

class MUTEX Mutex {
  CheckedMutex checked_;
 public:
  constexpr Mutex(MutexType type = MutexUnchecked) : checked_(type) {}

  void Lock() ACQUIRE() {
    checked_.Lock();
...
compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp
448 ↗(On Diff #360203)

can you land boilerplate like this in a separate patches?

vitalybuka added inline comments.Jul 20 2021, 11:10 PM
compiler-rt/lib/sanitizer_common/sanitizer_mutex.cpp
66 ↗(On Diff #360203)

uptr and now (int) cast?

Sorry, typos.
Avoid cast (int) by using uptr?

dvyukov updated this revision to Diff 360373.Jul 21 2021, 12:39 AM
dvyukov marked 7 inline comments as done.

addressed comments

I've addressed all comments. PTAL. Now it's 4 commits:
https://github.com/dvyukov/llvm-project/pull/5/commits

compiler-rt/lib/sanitizer_common/sanitizer_mutex.cpp
46 ↗(On Diff #360203)

Done.
Const objects are static by default (that's why consts can be declared in header files). But I added static to non-const variables below.

198 ↗(On Diff #360203)

You mean separated into a separate commit? It's in a separate commit, this change contains 3, but did not find how to look at separate commits in Phabricator, so I uploaded this to github as well:
https://github.com/dvyukov/llvm-project/pull/5/commits

compiler-rt/lib/sanitizer_common/sanitizer_mutex.h
152

I used inheritance for the purposes of EBO:
https://en.cppreference.com/w/cpp/language/ebo
I would not like to make release Mutex larger than it could be.

I've addressed all comments. PTAL. Now it's 4 commits:
https://github.com/dvyukov/llvm-project/pull/5/commits

I guess that's the feature you are looking for https://screenshot.googleplex.com/7N2V8vVmc8oKdmm

I've addressed all comments. PTAL. Now it's 4 commits:
https://github.com/dvyukov/llvm-project/pull/5/commits

I guess that's the feature you are looking for https://screenshot.googleplex.com/7N2V8vVmc8oKdmm

I mean if you upload them as a separate ones here, I'll stamp them and we move forward.

compiler-rt/lib/sanitizer_common/sanitizer_mutex.h
152
class MUTEX Mutex {
  [[no_unique_address]] CheckedMutex checked_;
 public:
  constexpr Mutex(MutexType type = MutexUnchecked) : checked_(type) {}

  void Lock() ACQUIRE() {
    checked_.Lock();

I've addressed all comments. PTAL. Now it's 4 commits:
https://github.com/dvyukov/llvm-project/pull/5/commits

I guess that's the feature you are looking for https://screenshot.googleplex.com/7N2V8vVmc8oKdmm

I mean if you upload them as a separate ones here, I'll stamp them and we move forward.

And we can see them here https://screenshot.googleplex.com/brREoodQu2LLmzx

compiler-rt/lib/sanitizer_common/sanitizer_mutex.cpp
198 ↗(On Diff #360203)

You mean separated into a separate commit? It's in a separate commit, this change contains 3, but did not find how to look at separate commits in Phabricator, so I uploaded this to github as well:
https://github.com/dvyukov/llvm-project/pull/5/commits

vitalybuka accepted this revision.Jul 21 2021, 12:58 PM
vitalybuka added inline comments.
compiler-rt/lib/tsan/rtl/tsan_defs.h
176

Something like this ?

enum class MutexType {
  Trace = MutexLastCommon,
  Report,
  SyncVar,
  Annotations,
  ...
};
compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
437–439

Wasn't ScopedIgnoreInterceptors relevant for existing code? If so maybe a separate patch?

compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
1135

is this leaked from another patch?

This revision is now accepted and ready to land.Jul 21 2021, 12:58 PM
vitalybuka added a comment.EditedJul 21 2021, 1:20 PM

After some poking around with arc tool I found this:

  1. you can upload entire branch with: git rebase -i --exec 'arc diff HEAD^' origin/main
  1. problem is that my "arc" didn't set parent/child relationship, and the reason is that it's not enabled on HEAD of arc. So you can set them manually in Phabricator or in arc diff message with "Depends on D????"
  1. Automatic "Depends on" can be restored with

arcanist$ git checkout dc42f51^

Then you can:
git rebase -i --exec 'arc diff HEAD^' origin/main
and produce stack similar to pull request on github like here: https://reviews.llvm.org/D106492

I mean if you upload them as a separate ones here, I'll stamp them and we move forward.

You mean I could upload all commits as separate phabricator reviews, right?
arc help diff says it will always upload diff with the current HEAD, so I would need to checkout each commit one-by-one and do 'arc diff' for each of them, right? and then link them in the phabricator UI?

dvyukov updated this revision to Diff 360794.Jul 22 2021, 6:51 AM

upload each commit into separate review

dvyukov updated this revision to Diff 360798.Jul 22 2021, 6:56 AM

re-upload in the hope that arc will auto-set dependent reviews

OK, I hope I managed to upload and link everything properly. I've uploaded this as 6 separate changes linked together.
PTAL

compiler-rt/lib/tsan/rtl/tsan_defs.h
176

I like enum classes, but this will require casts for all uses.
We pass these to Mutex ctor which accepts the sanitizer_common enum (different type).
What we do here is a bit non-standard, we declare part of enum in sanitizer_common and then "extend" it in tsan. I don't know how to do it with enum classes.

compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
1135

Right patch, but I am failing to upload this multi-commit change properly again. I did just 'arc diff' which uploaded only the last commit.

I would need to checkout each commit one-by-one and do 'arc diff' for each of them, right? and then link them in the phabricator UI?

Did you see my comment with git rebase?

I would need to checkout each commit one-by-one and do 'arc diff' for each of them, right? and then link them in the phabricator UI?

Did you see my comment with git rebase?

Yes, they answer my questions. I read them after writing this.

melver accepted this revision.Jul 22 2021, 10:53 AM
melver added inline comments.
compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
1149

I was thinking we could add a static assert here that the size is below the max, but as long as there is a CHECK-fail in the deadlock detector code that the last element is the terminator, this is not needed.

This revision was landed with ongoing or failed builds.Jul 23 2021, 12:13 AM
This revision was automatically updated to reflect the committed changes.
compiler-rt/lib/tsan/rtl/tsan_trace.h