[PATCH] D104649: Thread safety analysis: Rename parameters of ThreadSafetyAnalyzer::intersectAndWarn (NFC)

2021-06-25 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.

Looks good.  Thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D104649/new/

https://reviews.llvm.org/D104649

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D104261: Thread safety analysis: Always warn when dropping locks on back edges

2021-06-25 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.
This revision is now accepted and ready to land.

This looks good to me.  Thanks for the patch!  Since you're adding a new 
warning, this may break some code somewhere, but since it's restricted to 
relockable managed locks, I'm not too worried...


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D104261/new/

https://reviews.llvm.org/D104261

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102026: Thread safety analysis: Allow exlusive/shared joins for managed and asserted capabilities

2021-05-25 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.
This revision is now accepted and ready to land.

Thanks for taking the time to discuss things with me.  :-)

Wrt. to the TEST_LOCKED_FUNCTION, I agree that you can simulate the behavior 
using Assert and Lock.  But that pattern is too general/powerful, because it 
also allows you to write nonsensical and unsound code.  Philosophically, static 
analysis is concerned with allowing things that are sound, but preventing 
things that are not, so I would prefer to allow the valid case, but warn on the 
nonsensical/unsound code.  The goal is not to provide powerful back doors so 
that you can squeeze anything past the checker -- doing so kind of defeats the 
point.  :-)  That being said, I'm not certainly no asking you to implement 
TEST_LOCKED functionality in this particular patch, and I totally understand 
that it may simply not be worth the effort.

Wrt. to unlocking an Assert, I see no problem.  It makes perfect sense to 
dynamically assert that a mutex is held, then do something, and then unlock the 
mutex afterwards; after all, the caller asserted that it was held before 
unlocking.  You shouldn't disallow that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102026/new/

https://reviews.llvm.org/D102026

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102026: Thread safety analysis: Allow exlusive/shared joins for managed and asserted capabilities

2021-05-24 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: clang/test/SemaCXX/warn-thread-safety-analysis.cpp:4570
 mu_.AssertHeld();
-mu_.Unlock();
-  }  // should this be a warning?
+mu_.Unlock(); // should this be a warning?
+  }

This function should have a warning because is not marked with UNLOCK_FUNCTION. 
 The lock was held on entry, and not held on exit.  So the original location of 
the comment, on the closing curly brace, was correct.  



Comment at: clang/test/SemaCXX/warn-thread-safety-analysis.cpp:4629
+  mu_.AssertHeld(); // expected-note {{the other acquisition of mutex 
'mu_' is here}}
+// FIXME: should instead warn because it's unclear whether we need to 
release or not.
+int b = a;

I'm not wild about having FIXMEs in test code.  I would prefer to have the 
patch actually issue a warning here (but see below).

HOWEVER, does the current code issue a warning in this situation?  If not, 
leave it as-is and keep the FIXME.  You can't make the analysis more strict 
without checking with the C++ compiler team at Google (which I am no longer 
on), because it may break the build on our end.



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102026/new/

https://reviews.llvm.org/D102026

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102026: Thread safety analysis: Allow exlusive/shared joins for managed and asserted capabilities

2021-05-24 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

I have a few concerns.  First, this patch introduces an inconsistency between 
managed and unmanaged locks.  For unmanaged locks, we warn, and //then assume 
the lock is held exclusively//.  For managed locks, we don't warn, but //assume 
it is held shared//.  The warn/not-warn is consistent with more relaxed 
handling of managed locks, but exclusive/shared difference could lead to 
confusion.  Both mechanisms are sound; they're just not consistent.  Any 
thoughts?

Second, the mixing of AssertHeld() and Lock() on different control flow 
branches looks very weird to me.  I can see one obvious case where you might 
want to do that, e.g.  if (mu_.is_locked()) mu_.AssertHeld(); else mu_.Lock().  
However, if a function locks mu_ on one branch, and assert mu_ on the other, 
then that usually indicates a problem.  It means that the lock-state going into 
that function was unknown; the programmer didn't know whether mu_ was locked or 
not, and that's never good.  The //only// valid condition in that case is to 
check whether mu_ is locked -- any other condition would be unsound.  The 
correct way to deal with this situation is to mark the is_locked() method with 
an attribute, e.g. TEST_LOCKED_FUNCTION, rather than relying on the AssertHeld 
mechanism.  That's a lot more work, but I would prefer to at least have a TODO 
comment indicating that the AssertHeld is a workaround, and restrict the mixing 
of assert/lock to managed locks in the mean time.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102026/new/

https://reviews.llvm.org/D102026

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D98747: Thread safety analysis: Don't warn about managed locks on join points

2021-04-06 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.
This revision is now accepted and ready to land.

I am convinced by your argument.  I think it is reasonable to assume that if 
someone is using an RAII object, then the underlying object is responsible for 
managing double locks/unlocks, and we can restrict our efforts to detecting 
race conditions.  Thanks for the detailed explanation!  :-)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D98747/new/

https://reviews.llvm.org/D98747

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D98747: Thread safety analysis: Don't warn about managed locks on join points

2021-03-24 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

Thanks for roping me into the conversation, Aaron, and sorry about the delay.  
I have mixed feelings about this patch.  With respect to the purpose of thread 
safety analysis, finding race conditions is obviously a major concern, because 
race conditions are hard to find in tests.  However, preventing deadlocks is 
almost as important, and can be even more important in certain critical 
applications.  The consequence of a double unlock is usually a crash or an 
exception with an error message.  The consequence of a double lock is often a 
deadlock, depending on the underlying thread library, which is a more serious 
problem that is harder to fix.  Thus, I am concerned about the change in the 
test case on line 2895, where a potential deadlock has gone from detected, to 
no warning.  Deadlocks are often not found in tests, because test coverage is 
never perfect over all possible control-flow paths.

The use cases here are also slightly different.  A MutexLock object uses the 
RAII design pattern to ensure that the underlying mutex is unlocked on every 
control flow path, and presumably includes logic to prevent double 
releases/unlocks, as is usually the case with RAII.  The RAII pattern is 
sufficiently robust that we can "trust the implementation", and relax static 
checks.  A MutexUnlock object inverts the RAII pattern.  Because a lock is 
being acquired on different control-flow paths, rather than being released, it 
may make sense to keep the stronger checks in order to guard against potential 
deadlocks.  On the other hand, we are still using RAII, so the implementer of 
MutexUnlock could presumably insert logic to guard against deadlocks if that 
was a concern.  Thus, I could be persuaded that deadlocks are less important in 
this particular case.

Is there a compelling reason for this change, other than consistency/symmetry 
concerns?  In other words, do you have real-world code where you are getting 
false positives when using MutexUnlock?  If so, then I am in favor of the 
change.  If not, then I tend to err on the side of "if it ain't broke don't fix 
it."  :-)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D98747/new/

https://reviews.llvm.org/D98747

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59523: Thread Safety: also look at ObjC methods

2019-03-22 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.
This revision is now accepted and ready to land.

The if logic does not enhance readability, but I suppose it can't be helped.  
Looks good to me.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59523/new/

https://reviews.llvm.org/D59523



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52578: Thread safety analysis: Allow scoped releasing of capabilities

2018-11-29 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.

Just to be clear, I'm approving the change, but I'd still like the methods to 
be renamed.  :-)


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D52578/new/

https://reviews.llvm.org/D52578



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52578: Thread safety analysis: Allow scoped releasing of capabilities

2018-11-15 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: lib/Analysis/ThreadSafety.cpp:951
+}
   } else {
+// We're removing the underlying mutex. Warn on double unlocking.

aaronpuchert wrote:
> aaronpuchert wrote:
> > delesley wrote:
> > > aaronpuchert wrote:
> > > > delesley wrote:
> > > > > I find this very confusing.  A lock here unlocks the underlying 
> > > > > mutex, and vice versa.  At the very least, some methods need to be 
> > > > > renamed, or maybe we can have separate classes for ScopedLockable and 
> > > > > ScopedUnlockable. 
> > > > I agree that it's confusing, but it follows what I think was the idea 
> > > > behind scoped capabilities: that they are also capabilities that can be 
> > > > acquired/released. Now since the scoped capability releases a mutex on 
> > > > construction (i.e. when it is acquired), it has to acquire the mutex 
> > > > when released. So the way it handles the released mutexes mirrors what 
> > > > happens on the scoped capability itself.
> > > > 
> > > > It's definitely not very intuitive, but I feel it's the most consistent 
> > > > variant with what we have already.
> > > > 
> > > > The nice thing about this is that it works pretty well with the 
> > > > existing semantics and allows constructs such as `MutexLockUnlock` (see 
> > > > the tests) that unlocks one mutex and locks another. Not sure if anyone 
> > > > needs this, but why not?
> > > A scoped_lockable object is not a capability, it is an object that 
> > > manages capabilities.  IMHO, conflating those two concepts is a bad idea, 
> > > and recipe for confusion.  You would not, for example, use a 
> > > scoped_lockable object in a guarded_by attribute.  
> > > 
> > > Unfortunately, the existing code tends to conflate "capabilities" and 
> > > "facts", which is my fault.  A scoped_lockable object is a valid fact -- 
> > > the fact records whether the object is in scope -- it's just not a valid 
> > > capability. 
> > > 
> > > Simply renaming the methods from handleLock/Unlock to  addFact/removeFact 
> > > would be a nice first step in making the code clearer, and would 
> > > distinguish between facts that refer to capabilities, and facts that 
> > > refer to scoped objects.  
> > > 
> > > 
> > > 
> > > 
> > Makes sense to me. I'll see if I can refactor some of the code to clarify 
> > this.
> > 
> > I think that we should also separate between unlocking the underlying 
> > mutexes and destructing the scoped_lockable, which is currently handled via 
> > the extra parameter `FullyRemove` of `handleUnlock`.
> Scoped capabilities are not the same as capabilities, but they are also more 
> than just facts. (Except if you follow 
> [Wittgenstein](https://en.wikipedia.org/wiki/Tractatus_Logico-Philosophicus#Proposition_1),
>  perhaps.) They can be released, and reacquired, which makes them more than 
> mere immutable facts. I think we can consider them as proxy capabilities. 
> They cannot directly protect any resource, but we can acquire and release 
> (actual) capabilities through them. That's why it doesn't sound crazy to me 
> to say that releasing a scoped capability might acquire an underlying mutex, 
> if that was released on construction of the scoped capability.
The notion of "proxy" is how scoped objects have always been treated in the 
past, but that's mostly a historical accident, rather than a well-reasoned 
design choice.  As a bit of history, the first version of thread safety 
analysis only tracked mutexes.  Thus, the original implementation pretended 
that a scoped object was a mutex, because that's the only thing that the 
analysis could deal with.

As the analysis grew more complex, I switched to the current system based on 
"facts".  There are a number of facts that are potentially useful in static 
analysis, such as whether one expression aliases another, and most of them 
don't look at all like capabilities.  IMHO, knowing whether an object is within 
scope falls into this class.  The basic feature of facts is that they are 
control flow dependent -- they can be added to sets, removed from sets, and 
removed from intersections at joint points in the CFG.  Renaming the methods to 
reflect this design will make future extensions easier to understand.

The only real argument for treating scoped lockable objects as proxies, which 
can be "locked" and "unlocked", is that you can (in a future patch) reuse the 
existing acquire_capability and release_capability attributes to support 
releasing and then re-acquiring the proxy.  It's a bit counter-intuitive, but 
the alternative is adding new attributes, which is also bad.

However, even if you reuse the existing attributes, when it comes time to 
define a ScopedUnlockable class, you *still* shouldn't provide methods named 
"lock" and "unlock", where "lock"  releases the underlying mutex, and "unlock" 
reacquires it.  That's bad API design which will be endlessly confusing to 
users.

Thus, I would still 

[PATCH] D52443: Thread safety analysis: Examine constructor arguments

2018-10-04 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added inline comments.
This revision is now accepted and ready to land.



Comment at: lib/Analysis/ThreadSafety.cpp:2046
   const CXXConstructorDecl *D = Exp->getConstructor();
   if (D && D->isCopyConstructor()) {
 const Expr* Source = Exp->getArg(0);

aaronpuchert wrote:
> delesley wrote:
> > As a side note, we should probably special-case the move constructor too, 
> > with AK_Written.  That should be in a separate patch, though, and needs to 
> > be sequestered under -Wthread-safety-beta, which is complicated.   
> I think your arguments from D52395 apply here as well: the move constructor 
> does not necessarily write. Many simple types are trivially move 
> constructible, and then the move constructor is effectively the same as the 
> copy constructor.
Good point.


Repository:
  rC Clang

https://reviews.llvm.org/D52443



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52578: Thread safety analysis: Allow scoped releasing of capabilities

2018-10-04 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: lib/Analysis/ThreadSafety.cpp:893
 private:
-  SmallVector UnderlyingMutexes;
+  enum UnderlyingCapabilityKind {
+UCK_Acquired,  ///< Any kind of acquired capability.

aaronpuchert wrote:
> delesley wrote:
> > IMHO, it would make more sense to break this into two properties (or bits): 
> > acquired/released and shared/exclusive. 
> We don't use the information (shared/exclusive) for acquired locks, but we 
> need two bits anyway, so why not.
The normal unlock doesn't distinguish between shared/exclusive, but there is a 
release_shared_capability which does...


Repository:
  rC Clang

https://reviews.llvm.org/D52578



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52578: Thread safety analysis: Allow scoped releasing of capabilities

2018-10-04 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: lib/Analysis/ThreadSafety.cpp:951
+}
   } else {
+// We're removing the underlying mutex. Warn on double unlocking.

aaronpuchert wrote:
> delesley wrote:
> > I find this very confusing.  A lock here unlocks the underlying mutex, and 
> > vice versa.  At the very least, some methods need to be renamed, or maybe 
> > we can have separate classes for ScopedLockable and ScopedUnlockable. 
> I agree that it's confusing, but it follows what I think was the idea behind 
> scoped capabilities: that they are also capabilities that can be 
> acquired/released. Now since the scoped capability releases a mutex on 
> construction (i.e. when it is acquired), it has to acquire the mutex when 
> released. So the way it handles the released mutexes mirrors what happens on 
> the scoped capability itself.
> 
> It's definitely not very intuitive, but I feel it's the most consistent 
> variant with what we have already.
> 
> The nice thing about this is that it works pretty well with the existing 
> semantics and allows constructs such as `MutexLockUnlock` (see the tests) 
> that unlocks one mutex and locks another. Not sure if anyone needs this, but 
> why not?
A scoped_lockable object is not a capability, it is an object that manages 
capabilities.  IMHO, conflating those two concepts is a bad idea, and recipe 
for confusion.  You would not, for example, use a scoped_lockable object in a 
guarded_by attribute.  

Unfortunately, the existing code tends to conflate "capabilities" and "facts", 
which is my fault.  A scoped_lockable object is a valid fact -- the fact 
records whether the object is in scope -- it's just not a valid capability. 

Simply renaming the methods from handleLock/Unlock to  addFact/removeFact would 
be a nice first step in making the code clearer, and would distinguish between 
facts that refer to capabilities, and facts that refer to scoped objects.  







Comment at: lib/Analysis/ThreadSafety.cpp:992
+FSet.removeLock(FactMan, UnderCp);
+FSet.addLock(FactMan, std::move(UnderEntry));
+  }

aaronpuchert wrote:
> delesley wrote:
> > Shouldn't this be outside of the else?
> If we don't find `UnderCp` anymore, the negation should be there already. But 
> I can also keep it outside if you like.
That's not necessarily true.  Not knowing whether a mutex is locked is 
different from knowing that it is unlocked. 

You're probably right in this case, because capabilities that are managed by 
scoped objects obey a more restricted set of rules.  But then, you're also 
extending the ways in which scoped objects can be used.  :-)



Repository:
  rC Clang

https://reviews.llvm.org/D52578



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52395: Thread safety analysis: Require exclusive lock for passing by non-const reference

2018-10-04 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

For future patches, please add Richard Trieu (rtr...@google.com) as a 
subscriber.  I will continue to try and do code reviews, but Richard is on the 
team that actually rolls out new compiler changes.  Thanks!

BTW, the issue is not just that changes may introduce false positives.  Even if 
it's a true positive, you risk breaking the build.


Repository:
  rC Clang

https://reviews.llvm.org/D52395



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52578: Thread safety analysis: Allow scoped releasing of capabilities

2018-09-27 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: lib/Analysis/ThreadSafety.cpp:893
 private:
-  SmallVector UnderlyingMutexes;
+  enum UnderlyingCapabilityKind {
+UCK_Acquired,  ///< Any kind of acquired capability.

IMHO, it would make more sense to break this into two properties (or bits): 
acquired/released and shared/exclusive. 



Comment at: lib/Analysis/ThreadSafety.cpp:916
+for (const auto  : ShrdRel)
+  UnderlyingMutexes.emplace_back(M.sexpr(), UCK_ReleasedExclusive);
   }

UCK_ReleasedShared?  (Shouldn't this have been caught by a test case?)



Comment at: lib/Analysis/ThreadSafety.cpp:926
+  FactMan, CapabilityExpr(UnderlyingMutex.getPointer(), false));
+  if ((UnderlyingMutex.getInt() == UCK_Acquired) == (Entry != nullptr)) {
 // If this scoped lock manages another mutex, and if the underlying

This if statement makes my head hurt.  Can you find a different way of 
expressing it?



Comment at: lib/Analysis/ThreadSafety.cpp:951
+}
   } else {
+// We're removing the underlying mutex. Warn on double unlocking.

I find this very confusing.  A lock here unlocks the underlying mutex, and vice 
versa.  At the very least, some methods need to be renamed, or maybe we can 
have separate classes for ScopedLockable and ScopedUnlockable. 



Comment at: lib/Analysis/ThreadSafety.cpp:992
+FSet.removeLock(FactMan, UnderCp);
+FSet.addLock(FactMan, std::move(UnderEntry));
+  }

Shouldn't this be outside of the else?


Repository:
  rC Clang

https://reviews.llvm.org/D52578



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52443: Thread safety analysis: Examine constructor arguments

2018-09-27 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: lib/Analysis/ThreadSafety.cpp:2046
   const CXXConstructorDecl *D = Exp->getConstructor();
   if (D && D->isCopyConstructor()) {
 const Expr* Source = Exp->getArg(0);

As a side note, we should probably special-case the move constructor too, with 
AK_Written.  That should be in a separate patch, though, and needs to be 
sequestered under -Wthread-safety-beta, which is complicated.   


Repository:
  rC Clang

https://reviews.llvm.org/D52443



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52443: Thread safety analysis: Examine constructor arguments

2018-09-27 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

This looks good, and resolves an outstanding bug that was on my list.   Thanks 
for the patch!




Comment at: lib/Analysis/ThreadSafety.cpp:1537
   void handleCall(const Expr *Exp, const NamedDecl *D, VarDecl *VD = nullptr);
+  void ExamineCallArguments(const FunctionDecl *FD,
+CallExpr::const_arg_iterator ArgBegin,

Nit: capitalization does not match other methods.


Repository:
  rC Clang

https://reviews.llvm.org/D52443



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52395: Thread safety analysis: Require exclusive lock for passing by non-const reference

2018-09-27 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

With respect to data, I really think these patches should be tested against 
Google's code base, because otherwise you're going to start seeing angry 
rollbacks.  However, I don't work on the C++ team any more, and I don't have 
time to do it.  When I was actively developing the analysis, I spent about 90% 
of my time just running tests and fixing the code base.  Each incremental 
improvement in the analysis itself was a hard upward slog.  If you're going to 
be adding lots of improvements, we need to have someone at Google running point.


Repository:
  rC Clang

https://reviews.llvm.org/D52395



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52395: Thread safety analysis: Require exclusive lock for passing by non-const reference

2018-09-27 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

I have mixed feelings about this patch.  When you pass an object to a function, 
either by pointer or by reference, no actual load from memory has yet occurred. 
 Thus, there is a real risk of false positives; what you are saying is that the 
function *might* read or write from protected memory, not that it actually 
will.  In fact, the false positive rate is high enough that this particular 
warning is sequestered under -Wthread-safety-reference, and is not used with 
warnings-as-errors at Google.

In theory, the correct way to deal with references is to make GUARDED_BY an 
attribute of the type, rather than an attribute of the data member; that way 
taking the address of a member, or passing it by reference, wouldn't cast away 
the annotation.  But that would require a properly parametric dependent type 
system for C++, which is pretty much impossible.  So you're left with two bad 
options: either issue a warning eagerly, and deal with false positives, or 
suppress the warning, and deal with false negatives.  At Google, false 
positives usually break the build, which has forced me to prefer false 
negatives in most cases; my strategy has been to gradually tighten the analysis 
bit by bit.  Thankfully, that's less of a concern here.

Adding to the difficulty is the fact that the correct use of "const" in 
real-world C++ code is spotty at best.  There is LOTS of code that arguably 
should be using const, but doesn't for various reasons.  E.g. if program A 
calls library B, and library B forgot to provide const-qualified versions of a 
few methods, than A has to make a choice: either drop the const qualifier, or 
insert ugly const-casts, neither of which is pleasant.  In other-words, 
non-constness has a tendency to propagate through the code base, and you can't 
depend on "const" being accurate.

I have two recommendations.  First think the default behavior should be to 
require only a read-only lock, as it currently does.  That's a compromise 
between the "false-positive" and "false-negative" camps.  It catches a lot of 
errors, because you have to hold the lock in some way, but doesn't require 
accurate const-ness.  For people who want more accuracy, there should be a 
different variant of the warning -- maybe -Wthread-safety-reference-precise?  
Between beta/precise/reference etc. there are a now a lot of analysis options, 
and I would love to consolidate them in some fashion.  However, different code 
bases have different needs, and I think "one size fits all" is not really 
appropriate.

Second, there needs to be a thread-safety-variant of "const_cast" -- i.e. a way 
to pass a reference to a function without triggering the warning.  That may 
already be possible via clever use of our current annotations, or you may have 
to fiddle with something, but it needs to appear in the test cases.


Repository:
  rC Clang

https://reviews.llvm.org/D52395



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51187: [RFC] Thread safety analysis: Track status of scoped capability

2018-09-21 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

In https://reviews.llvm.org/D51187#1241354, @aaronpuchert wrote:

> Thanks for pointing out my error! Ignoring the implementation for a moment, 
> do you think this is a good idea or will it produce too many false positives? 
> Releasable/relockable scoped capabilities that I have seen keep track of the 
> status, so it makes sense, but maybe there are others out there.


I think this is probably a good idea.  Code which manipulates the underlying 
mutex while it is being managed by another object is a recipe for trouble.  
It's hard for me to guess how many false positives it will generate without 
actually running it over our code base, which I personally don't have time to 
do right now.  It should definitely go in -Wthread-safety-beta so it won't 
break the build.  Unfortunately, the before/after checks are still in 
thread-safety-beta, and they should really be moved out of beta before 
something else is moved in.  The good news is that Matthew O'Niel just 
volunteered to do that.  That is, unfortunately, not a trivial operation, so it 
may be some weeks before he's done.


Repository:
  rC Clang

https://reviews.llvm.org/D51187



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51187: [RFC] Thread safety analysis: Track status of scoped capability

2018-09-19 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: lib/Analysis/ThreadSafety.cpp:929
+  return Handler.handleDoubleLock(DiagKind, entry.toString(), entry.loc());
+Locked = true;
+

It's been a while since I last looked at this code, but I don't think you can 
use mutable fields in a FactEntry.  The analysis creates a FactSet for each 
program point, but each FactSet simply has pointers (FactIDs) for the 
underlying FactEntries.  If you change the definition of a FactEntry, it will 
change that definition for every program point.  So if you do an unlock on one 
side of a branch, and change the underlying FactEntry to reflect that, then 
analysis will then think you have also done the unlock on the other side of the 
branch.  

Any changes should always be done by adding or removing entries from the 
FactSet, not by mutating the underlying FactEntries.



Repository:
  rC Clang

https://reviews.llvm.org/D51187



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D52200: Thread safety analysis: Handle ObjCIvarRefExpr in SExprBuilder::translate

2018-09-19 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added inline comments.



Comment at: lib/Analysis/ThreadSafetyCommon.cpp:362
+  til::Project *P = new (Arena) til::Project(E, D);
+  if (hasCppPointerType(BE))
+P->setArrow(true);

aaronpuchert wrote:
> rjmccall wrote:
> > aaron.ballman wrote:
> > > I feel like this will always return false. However, I wonder if 
> > > `IVRE->getBase()->isArrow()` is more appropriate here?
> > The base of an `ObjCIvarRefExpr` will never directly be a C pointer type.  
> > I don't know whether this data structure looks through casts, but it's 
> > certainly *possible* to cast arbitrarily weird C stuff to ObjC pointer 
> > type.  On the other hand, by and large nobody actually ever does that, so I 
> > wouldn't make a special case for it here.
> > 
> > `ObjCIvarRefExpr` just has an `isArrow()` method directly if this is just 
> > supposed to be capturing the difference between `.` and `->`.  But then, so 
> > does `MemberExpr`, and in that case you're doing this odd analysis of the 
> > base instead of trusting `isArrow()`, so I don't know what to tell you to 
> > do.
> > 
> > Overall it is appropriate to treat an ObjC ivar reference as a perfectly 
> > ordinary projection.  The only thing that's special about it is that the 
> > actual offset isn't necessarily statically known, but ivars still behave as 
> > if they're all independently declared, so I wouldn't worry about it.
> I had wondered about this as well, but when I changed `hasCppPointerType(BE)` 
> to `ME->isArrow()` in the `MemberExpr` case, I got some test failures. For 
> example:
> 
> ```
> struct Foo {
>   int a __attribute__((guarded_by(mu)));
>   Mutex mu;
> };
> 
> void f() {
>   Foo foo;
>   foo.a = 5; // \
> // expected-warning{{writing variable 'a' requires holding mutex 'foo.mu' 
> exclusively}}
> }
> ```
> 
> Instead we warn `writing variable 'a' requires holding mutex 'foo->mu' 
> exclusively`. That's not right.
> 
> The expression (`ME`) we are processing is `mu` from the attribute on `a`, 
> which the compiler sees as `this->mu`. So we get `ME->isArrow() == true` and 
> `ME->getBase()` is a `CXXThisExpr`.
> 
> Basically the `translate*` functions do a substitution. They try to derive 
> `foo.mu` from `this->mu` on the `a` member and the expression `foo.a`. The 
> annotation `this->mu` is the expression we get as parameter, and `foo.a` is 
> encoded in the `CallingContext`.
> 
> The information whether `foo.a` is an arrow (it isn't) seems to be in the 
> `CallingContext`'s `SelfArrow` member.
This is a recurring problem.  The fundamental issue is the analysis must 
compare expressions for equality, but many C++ expressions are syntactically 
different but semantically the same, like  ()->mu  and  foo.mu.  It's 
particularly problematic because (as Aaron notes) we frequently substitute 
arguments when constructing expressions, which makes it easy to get things like 
()->mu instead of foo.mu, when substituting  for a pointer argument. 

The purpose of the TIL is to translate C++ expressions into a simpler, 
lower-level IR, where syntactic equality in the IR corresponds to semantic 
equality between expressions.  The TIL doesn't distinguish between pointers and 
references, doesn't distinguish between -> and ., and ignores * and & as 
no-ops.  But then we have to recover the distinction between -> and . when we 
generate an error message.

In the presence of substitution, you can't go by whether the source syntax has 
an ->.  You have to look at whether the type of the underlying argument (after 
stripping away * and &) requires an arrow.

I know nothing about objective C, so I don't know what the right answer is here.


Repository:
  rC Clang

https://reviews.llvm.org/D52200



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D51901: Thread Safety Analysis: warnings for attributes without arguments

2018-09-19 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.
This revision is now accepted and ready to land.

This looks okay to me, but I have not tested it on a large code base to see if 
it breaks anything.




Comment at: lib/Sema/SemaDeclAttr.cpp:589
+<< AL << MD->getParent();
+} else
+  S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member)

Curly braces around the else section.


Repository:
  rC Clang

https://reviews.llvm.org/D51901



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49885: Thread safety analysis: Allow relockable scopes

2018-08-20 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.

This looks good to me.  Thanks for the patch.




Comment at: lib/Analysis/ThreadSafety.cpp:932
+  // We're relocking the underlying mutexes. Warn on double locking.
+  if (FSet.findLock(FactMan, UnderCp))
+Handler.handleDoubleLock(DiagKind, UnderCp.toString(), entry.loc());

Minor nit.  Use curly braces on the if, to match the else.


Repository:
  rC Clang

https://reviews.llvm.org/D49885



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D49355: Thread safety analysis: Allow lock upgrading and downgrading

2018-07-25 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.
This revision is now accepted and ready to land.

Looks good to me.  Thanks for the patch, and my apologies for the slow 
response.  (I'm on a different project now, so I'm afraid thread safety doesn't 
always get the attention from me that it deserves.)

  -DeLesley


Repository:
  rC Clang

https://reviews.llvm.org/D49355



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D41933: handle scoped_lockable objects being returned by value in C++17

2018-01-11 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.

LGTM.  Thanks, Richard!


Repository:
  rC Clang

https://reviews.llvm.org/D41933



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36237: Reland "Thread Safety Analysis: fix assert_capability.", add warnings

2017-08-07 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

Overall looks good.  However, I would change the wording on the warning to the 
following.  The terms "free function" and "instance method" may be confusing to 
some people.  Also, warn_thread_attribute_noargs_static_method should not 
mention the capability attribute, which is checked separately in 
warn_thread_attribute_noargs_not_lockable.

def warn_thread_attribute_noargs_not_method: ... "%0 attribute without 
arguments can only be applied to a method of a class." ...
def warn_thread_attribute_noargs_static_method: ... "%0 attribute without 
arguments cannot be applied a static method." ...


https://reviews.llvm.org/D36237



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D36122: Thread Safety Analysis: fix assert_capability.

2017-08-01 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley accepted this revision.
delesley added a comment.
This revision is now accepted and ready to land.

Thanks!


Repository:
  rL LLVM

https://reviews.llvm.org/D36122



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D29685: Lit C++11 Compatibility - Function Attributes

2017-02-13 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

I agree with Aaron here.  Those thread safety errors are supposed to fire; 
simply disabling the unit tests because they no longer fire is not acceptable.  
I also don't understand how this could be a bug with the thread safety 
analysis, since these particular errors are issued when the attributes are 
parsed, not when the analysis is run.   I haven't looked at the relevant code 
in a long time; have there been significant changes to the attribute-parsing 
mechanism?  There's no member initialization going on here, so why would 
changes to member initialization have this side effect?  I'm confused.

  DeLesley


https://reviews.llvm.org/D29685



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D28520: Disable -Wthread-safety-analysis for some functions in __thread_support

2017-01-26 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

This looks good to me.


https://reviews.llvm.org/D28520



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D28520: Disable -Wthread-safety-analysis for some functions in __thread_support

2017-01-25 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

The big question for me is whether these functions are exposed as part of the 
public libcxx API, or whether they are only used internally.  (Again, I'm not a 
libcxx expert.)  If they are part of the public API, then users may want to 
switch them on and off in their own code.  In that case, I'm happy with the 
current variant.

If they are only used internally, then no_thread_safety_analysis is probably 
the correct option.  (Unless, of course, the libcxx developers want to start 
using the analysis themselves, but I suspect they don't.)


https://reviews.llvm.org/D28520



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D28520: Disable -Wthread-safety-analysis for some functions in __thread_support

2017-01-17 Thread Delesley Hutchins via Phabricator via cfe-commits
delesley added a comment.

Sorry about the slow response.   My main concern here is that the thread safety 
analysis was designed for use with a library that wraps the system mutex in a 
separate Mutex class.  We did that specifically to avoid breaking anything; 
code has to opt-in to the static checking by defining and using a Mutex class, 
and the API of that class is restricted to calls that can be easily checked via 
annotations.  Including attributes directly in the standard library has the 
potential to cause lots of breakage and false positives.

Is there some way to control the #ifdefs so that the annotations are turned off 
by default for everyone except possibly freebsd, but there's still a way to 
turn them on for users who want to see the warnings?  I'm not a libcxx expert.


https://reviews.llvm.org/D28520



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits