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

Aaron Puchert via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 14 16:19:11 PDT 2020


aaronpuchert added reviewers: aaron.ballman, aaronpuchert.
aaronpuchert added a comment.

We don't really have a good understanding of `ASSERT_CAPABILITY` ourselves. For example, there is this loophole:

  void h() {
    mu.AssertHeld();
    mu.Unlock();
  }

One would expect to get a warning forcing the user to add a `RELEASE(mu)`annotation on `h`, but there is none. Should we disallow releasing of asserted capabilities?

In some way, `ASSERT_CAPABILITY` is a bit of an outsider that doesn't really fit in with the other attributes.



================
Comment at: clang/docs/ThreadSafetyAnalysis.rst:450
 
-These are attributes on a function or method that does a run-time test to see
-whether the calling thread holds the given capability.  The function is assumed
-to fail (no return) if the capability is not held.  See :ref:`mutexheader`,
-below, for example uses.
+These are attributes on a function or method which asserts the calling thread
+already holds the given capability, for example by performing a run-time test
----------------
The assertion is just a promise though, so it could only happen in debug builds, for example.


================
Comment at: clang/docs/ThreadSafetyAnalysis.rst:452
+already holds the given capability, for example by performing a run-time test
+and terminating or throwing if the capability is not held.  Presence of this
+annotation causes the analysis to assume the capability is held at the point of
----------------
That's an interesting point. We currently do assume that the capability is held even when an exception is thrown, although that's primarily because Clang's source-level CFG doesn't really model exception handling that well:

```
Mutex mu;
bool a GUARDED_BY(mu);

void except() {
  try {
    mu.AssertHeld();
  } catch (...) {
    a = 0; // No warning.
  }
}
```

We can't warn there because `AssertHeld` might terminate in case the mutex isn't held.

Not sure if we need to clarify this here: we just assume that the capability is held on a regular return. The other case is basically UB for us.


================
Comment at: clang/docs/ThreadSafetyAnalysis.rst:453
+and terminating or throwing if the capability is not held.  Presence of this
+annotation causes the analysis to assume the capability is held at the point of
+the call. See :ref:`mutexheader`, below, for example uses.
----------------
It's implemented a bit differently:

```
Mutex mu;
bool a GUARDED_BY(mu);

void f() {
  a = 0; // warning.
  mu.AssertHeld();
  a = 0; // Ok.
}
```

If we were to assume that `mu` is held at the call site, it would also be held right before it.

I'm not sure if this is the right behavior, but assuming that it is, calling an `ASSERT_CAPABILITY` function introduces an assumption which can be used from that point on, and which disappears on join points with branches that don't have the assumption.


================
Comment at: clang/docs/ThreadSafetyAnalysis.rst:456-457
+
+The given capability must be held on entry to the function, or the function is
+assumed to fail (no return).
 
----------------
"The function is assumed to return only if the given capability is held."?


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