Skip to content

Commit cff267e

Browse files
committed
Thread Safety Analysis: Support reentrant capabilities
Introduce the `reentrant_capability` attribute, which may be specified alongside the `capability(..)` attribute to denote that the defined capability type is reentrant. Marking a capability as reentrant means that acquiring the same capability multiple times is safe, and does not produce warnings on attempted re-acquisition. The most significant changes required are plumbing to propagate if the attribute is present to a CapabilityExpr, and then introducing a ReentrancyCount to FactEntry that can be incremented while a fact remains in the FactSet. Care was taken to avoid increasing the size of both CapabilityExpr and FactEntry by carefully allocating free bits of CapabilityExpr::CapExpr and the bitset respectively.
1 parent c60ccbc commit cff267e

11 files changed

+481
-83
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ Improvements to Clang's diagnostics
340340
as function arguments or return value respectively. Note that
341341
:doc:`ThreadSafetyAnalysis` still does not perform alias analysis. The
342342
feature will be default-enabled with ``-Wthread-safety`` in a future release.
343+
- The :doc:`ThreadSafetyAnalysis` now supports reentrant capabilities.
343344
- Clang will now do a better job producing common nested names, when producing
344345
common types for ternary operator, template argument deduction and multiple return auto deduction.
345346
- The ``-Wsign-compare`` warning now treats expressions with bitwise not(~) and minus(-) as signed integers

clang/docs/ThreadSafetyAnalysis.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,16 @@ class can be used as a capability. The string argument specifies the kind of
434434
capability in error messages, e.g. ``"mutex"``. See the ``Container`` example
435435
given above, or the ``Mutex`` class in :ref:`mutexheader`.
436436

437+
REENTRANT
438+
---------
439+
440+
``REENTRANT`` is an attribute on capability classes, denoting that they are
441+
reentrant. Marking a capability as reentrant means that acquiring the same
442+
capability multiple times is safe.
443+
444+
Note that acquiring the same capability with different access privileges
445+
(exclusive vs. shared) again is not considered reentrant by the analysis.
446+
437447
.. _scoped_capability:
438448

439449
SCOPED_CAPABILITY
@@ -846,6 +856,9 @@ implementation.
846856
#define CAPABILITY(x) \
847857
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
848858

859+
#define REENTRANT \
860+
THREAD_ANNOTATION_ATTRIBUTE__(reentrant_capability)
861+
849862
#define SCOPED_CAPABILITY \
850863
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
851864

clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,14 @@ class CFGWalker {
272272
class CapabilityExpr {
273273
private:
274274
/// The capability expression and flags.
275-
llvm::PointerIntPair<const til::SExpr *, 1, unsigned> CapExpr;
275+
llvm::PointerIntPair<const til::SExpr *, 2, unsigned> CapExpr;
276276

277277
/// The kind of capability as specified by @ref CapabilityAttr::getName.
278278
StringRef CapKind;
279279

280280
public:
281281
static constexpr unsigned FlagNegative = 1u << 0;
282+
static constexpr unsigned FlagReentrant = 1u << 1;
282283

283284
CapabilityExpr() : CapExpr(nullptr, 0) {}
284285
CapabilityExpr(const til::SExpr *E, StringRef Kind, unsigned Flags)
@@ -291,6 +292,7 @@ class CapabilityExpr {
291292
const til::SExpr *sexpr() const { return CapExpr.getPointer(); }
292293
StringRef getKind() const { return CapKind; }
293294
bool negative() const { return CapExpr.getInt() & FlagNegative; }
295+
bool reentrant() const { return CapExpr.getInt() & FlagReentrant; }
294296

295297
CapabilityExpr operator!() const {
296298
return CapabilityExpr(CapExpr.getPointer(), CapKind,
@@ -392,7 +394,7 @@ class SExprBuilder {
392394
til::LiteralPtr *createVariable(const VarDecl *VD);
393395

394396
// Create placeholder for this: we don't know the VarDecl on construction yet.
395-
std::pair<til::LiteralPtr *, StringRef>
397+
std::tuple<til::LiteralPtr *, StringRef, unsigned>
396398
createThisPlaceholder(const Expr *Exp);
397399

398400
// Translate a clang statement or expression to a TIL expression.

clang/include/clang/Basic/Attr.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3990,6 +3990,13 @@ def LocksExcluded : InheritableAttr {
39903990
let Documentation = [Undocumented];
39913991
}
39923992

3993+
def ReentrantCapability : InheritableAttr {
3994+
let Spellings = [Clang<"reentrant_capability">];
3995+
let Subjects = SubjectList<[Record, TypedefName]>;
3996+
let Documentation = [Undocumented];
3997+
let SimpleHandler = 1;
3998+
}
3999+
39934000
// C/C++ consumed attributes.
39944001

39954002
def Consumable : InheritableAttr {

0 commit comments

Comments
 (0)