[PATCH] D87629: Thread safety analysis: Improve documentation for ASSERT_CAPABILITY

Aaron Puchert via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 17 00:38:59 PDT 2020


aaronpuchert added a comment.

In D87629#2278383 <https://reviews.llvm.org/D87629#2278383>, @ajtowns wrote:

> Not sure the `try { AssertHeld } catch (...) { a = 0; }` example reveals very much: it seems like thread safety annotations aren't checked within a catch block at all?
>
>   Mutex m;
>   int i GUARDED_BY(m);
>   
>   static void thrower() { throw std::exception(); }
>   void f() { i = 1; }
>   void g() {
>       try {
>           thrower();
>       } catch (...) {
>           i = 5;
>       }
>       i = 6;
>   }
>
> gives me warnings for `i=1` and `i=6` but not `i=5` ?

It's not we don't check catch-blocks, but rather that the Clang CFG is incomplete:

   [B5 (ENTRY)]
     Succs (1): B4
  
   [B1]
     1: 6
     2: i
     3: [B1.2] = [B1.1]
     Preds (2): B3 B4
     Succs (1): B0
  
   [B2]
     T: try ...
     Succs (1): B3
  
   [B3]
    catch (...):
     1: catch (...) {
      [B3.4];
  }
     2: 5
     3: i
     4: [B3.3] = [B3.2]
     Preds (1): B2
     Succs (1): B1
  
   [B4]
     1: thrower
     2: [B4.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(void))
     3: [B4.2]()
     Preds (1): B5
     Succs (1): B1
  
   [B0 (EXIT)]
     Preds (1): B1

There is no edge from the `thrower` call to `B2` or `B3`. We can turn on "exception handling edges" from non-noexcept calls to catch blocks, but that's a bigger change and it would affect other warnings as well. There are also performance problems. (https://bugs.llvm.org/show_bug.cgi?id=43311)

> Using a dummy RAII class with SCOPED_CAPABILITY that does ACQUIRE/RELEASE without modifying the actual mutex seems like it behaves more sensibly to me...

Well, you clearly don't acquire or release anything. It's just a hack that seems to solve the problem, but doesn't really (see below).

>   class SCOPED_LOCKABLE assumer
>   {
>   public:
>       assumer(Mutex& m_) EXCLUSIVE_LOCK_FUNCTION(m_) { }
>       ~assumer() UNLOCK_FUNCTION() { }
>   };
>   
>   void h(bool b) {
>       try {
>           if (b) thrower();
>           i = 7;
>           assumer a(m);
>           i = 8;
>       } catch (...) { }
>       i = 9;
>   }
>
> gives me warnings for both `i=7` and `i=9` but allows `i=8`.

You're cherry-picking here. If you move `i=9` into the catch block, there is still no warning. And if you remove `if (b) thrower();` we wouldn't want the warning, because the assertion could be calling `std::abort` and then we'd have a false positive.

Assertions aren't scoped. The easiest way to see that is that destructor doesn't do anything.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87629



More information about the cfe-commits mailing list