r227997 - Thread Safety Analysis: add support for before/after annotations on mutexes.

Justin Bogner mail at justinbogner.com
Tue Feb 3 12:08:27 PST 2015


DeLesley Hutchins <delesley at google.com> writes:
> Author: delesley
> Date: Tue Feb  3 12:17:48 2015
> New Revision: 227997
>
> URL: http://llvm.org/viewvc/llvm-project?rev=227997&view=rev
> Log:
> Thread Safety Analysis: add support for before/after annotations on mutexes.
> These checks detect potential deadlocks caused by inconsistent lock
> ordering.  The checks are implemented under the -Wthread-safety-beta flag.

This seems to be failing tests on a lot of bots, but it doesn't revert
cleanly (follow ups?). Can you please fix or revert?

http://lab.llvm.org:8080/green/job/clang-stage1-cmake-RA-incremental_check/3975/
http://lab.llvm.org:8011/builders/clang-native-arm-cortex-a9/builds/25095
http://lab.llvm.org:8011/builders/clang-hexagon-elf/builds/22225
http://lab.llvm.org:8011/builders/clang-x86_64-ubuntu-gdb-75/builds/19880

> Modified:
>     cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h
>     cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>     cfe/trunk/include/clang/Sema/Sema.h
>     cfe/trunk/lib/Analysis/ThreadSafety.cpp
>     cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
>     cfe/trunk/lib/Sema/Sema.cpp
>     cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
>
> Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h Tue Feb  3 12:17:48 2015
> @@ -26,6 +26,8 @@
>  namespace clang {
>  namespace threadSafety {
>  
> +class BeforeSet;
> +
>  /// This enum distinguishes between different kinds of operations that may
>  /// need to be protected by locks. We use this enum in error handling.
>  enum ProtectedOperationKind {
> @@ -183,6 +185,14 @@ public:
>    virtual void handleFunExcludesLock(StringRef Kind, Name FunName,
>                                       Name LockName, SourceLocation Loc) {}
>  
> +
> +  /// Warn that L1 cannot be acquired before L2.
> +  virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name,
> +                                        Name L2Name, SourceLocation Loc) {}
> +
> +  /// Warn that there is a cycle in acquired_before/after dependencies.
> +  virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {}
> +
>    /// Called by the analysis when starting analysis of a function.
>    /// Used to issue suggestions for changes to annotations.
>    virtual void enterFunction(const FunctionDecl *FD) {}
> @@ -203,7 +213,8 @@ private:
>  /// at the end of each block, and issue warnings for thread safety violations.
>  /// Each block in the CFG is traversed exactly once.
>  void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
> -                             ThreadSafetyHandler &Handler);
> +                             ThreadSafetyHandler &Handler,
> +                             BeforeSet **Bset);
>  
>  /// \brief Helper function that returns a LockKind required for the given level
>  /// of access.
>
> Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
> +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Tue Feb  3 12:17:48 2015
> @@ -286,6 +286,14 @@ public:
>              sx::partiallyMatches(CapExpr, other.CapExpr);
>    }
>  
> +  const ValueDecl* valueDecl() const {
> +    if (Negated)
> +      return nullptr;
> +    if (auto *P = dyn_cast<til::Project>(CapExpr))
> +      return P->clangDecl();
> +    return nullptr;
> +  }
> +
>    std::string toString() const {
>      if (Negated)
>        return "!" + sx::toString(CapExpr);
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb  3 12:17:48 2015
> @@ -2394,6 +2394,13 @@ def warn_fun_excludes_mutex : Warning<
>  def warn_cannot_resolve_lock : Warning<
>    "cannot resolve lock expression">,
>    InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
> +def warn_acquired_before : Warning<
> +  "%0 '%1' must be acquired before '%2'">,
> +  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
> +def warn_acquired_before_after_cycle : Warning<
> +  "Cycle in acquired_before/after dependencies, starting with '%0'">,
> +  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
> +
>  
>  // Thread safety warnings negative capabilities
>  def warn_acquire_requires_negative_cap : Warning<
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb  3 12:17:48 2015
> @@ -199,6 +199,11 @@ namespace sema {
>    class TemplateDeductionInfo;
>  }
>  
> +namespace threadSafety {
> +  class BeforeSet;
> +  void threadSafetyCleanup(BeforeSet* Cache);
> +}
> +
>  // FIXME: No way to easily map from TemplateTypeParmTypes to
>  // TemplateTypeParmDecls, so we have this horrible PointerUnion.
>  typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
> @@ -6708,6 +6713,7 @@ public:
>  
>    /// \brief Worker object for performing CFG-based warnings.
>    sema::AnalysisBasedWarnings AnalysisWarnings;
> +  threadSafety::BeforeSet *ThreadSafetyDeclCache;
>  
>    /// \brief An entity for which implicit template instantiation is required.
>    ///
>
> Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
> +++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Tue Feb  3 12:17:48 2015
> @@ -101,17 +101,22 @@ private:
>    LockKind          LKind;            ///<  exclusive or shared
>    SourceLocation    AcquireLoc;       ///<  where it was acquired.
>    bool              Asserted;         ///<  true if the lock was asserted
> +  bool              Declared;         ///<  true if the lock was declared
>  
>  public:
>    FactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc,
> -            bool Asrt)
> -      : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt) {}
> +            bool Asrt, bool Declrd = false)
> +      : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt),
> +        Declared(Declrd) {}
>  
>    virtual ~FactEntry() {}
>  
> -  LockKind          kind()       const { return LKind;    }
> +  LockKind          kind()       const { return LKind;      }
>    SourceLocation    loc()        const { return AcquireLoc; }
>    bool              asserted()   const { return Asserted; }
> +  bool              declared()   const { return Declared; }
> +
> +  void setDeclared(bool D) { Declared = D; }
>  
>    virtual void
>    handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan,
> @@ -231,14 +236,56 @@ public:
>  
>    FactEntry *findPartialMatch(FactManager &FM,
>                                const CapabilityExpr &CapE) const {
> -    auto I = std::find_if(begin(), end(), [&](FactID ID) {
> +    auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool {
>        return FM[ID].partiallyMatches(CapE);
>      });
>      return I != end() ? &FM[*I] : nullptr;
>    }
> +
> +  bool containsMutexDecl(FactManager &FM, const ValueDecl* Vd) const {
> +    auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool {
> +      return FM[ID].valueDecl() == Vd;
> +    });
> +    return I != end();
> +  }
> +};
> +
> +
> +class ThreadSafetyAnalyzer;
> +
> +
> +class BeforeSet {
> +private:
> +  typedef SmallVector<const ValueDecl*, 4>  BeforeVect;
> +
> +  struct BeforeInfo {
> +    BeforeInfo() : Vect(nullptr), Visited(false) { }
> +
> +    std::unique_ptr<BeforeVect> Vect;
> +    int                         Visited;
> +  };
> +
> +  typedef llvm::DenseMap<const ValueDecl*, BeforeInfo>  BeforeMap;
> +  typedef llvm::DenseMap<const ValueDecl*, bool>        CycleMap;
> +
> +public:
> +  BeforeSet() { }
> +
> +  BeforeInfo* insertAttrExprs(const ValueDecl* Vd,
> +                              ThreadSafetyAnalyzer& Analyzer);
> +
> +  void checkBeforeAfter(const ValueDecl* Vd,
> +                        const FactSet& FSet,
> +                        ThreadSafetyAnalyzer& Analyzer,
> +                        SourceLocation Loc, StringRef CapKind);
> +
> +private:
> +  BeforeMap BMap;
> +  CycleMap  CycMap;
>  };
>  
>  
> +
>  typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext;
>  class LocalVariableMap;
>  
> @@ -853,6 +900,7 @@ public:
>  /// \brief Class which implements the core thread safety analysis routines.
>  class ThreadSafetyAnalyzer {
>    friend class BuildLockset;
> +  friend class BeforeSet;
>  
>    llvm::BumpPtrAllocator Bpa;
>    threadSafety::til::MemRegionRef Arena;
> @@ -864,9 +912,11 @@ class ThreadSafetyAnalyzer {
>    FactManager               FactMan;
>    std::vector<CFGBlockInfo> BlockInfo;
>  
> +  BeforeSet* GlobalBeforeSet;
> +
>  public:
> -  ThreadSafetyAnalyzer(ThreadSafetyHandler &H)
> -     : Arena(&Bpa), SxBuilder(Arena), Handler(H) {}
> +  ThreadSafetyAnalyzer(ThreadSafetyHandler &H, BeforeSet* Bset)
> +     : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {}
>  
>    bool inCurrentScope(const CapabilityExpr &CapE);
>  
> @@ -907,6 +957,136 @@ public:
>    void runAnalysis(AnalysisDeclContext &AC);
>  };
>  
> +
> +
> +/// Process acquired_before and acquired_after attributes on Vd.
> +BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd,
> +    ThreadSafetyAnalyzer& Analyzer) {
> +  // Create a new entry for Vd.
> +  auto& Entry = BMap.FindAndConstruct(Vd);
> +  BeforeInfo* Info = &Entry.second;
> +  BeforeVect* Bv = nullptr;
> +
> +  const AttrVec &ArgAttrs = Vd->getAttrs();
> +  for (Attr* At : ArgAttrs) {
> +    switch (At->getKind()) {
> +      case attr::AcquiredBefore: {
> +        auto *A = cast<AcquiredBeforeAttr>(At);
> +
> +        // Create a new BeforeVect for Vd if necessary.
> +        if (!Bv) {
> +          Bv = new BeforeVect;
> +          Info->Vect.reset(Bv);
> +        }
> +        // Read exprs from the attribute, and add them to BeforeVect.
> +        for (const auto *Arg : A->args()) {
> +          CapabilityExpr Cp =
> +            Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);
> +          if (const ValueDecl *Cpvd = Cp.valueDecl()) {
> +            Bv->push_back(Cpvd);
> +            auto It = BMap.find(Cpvd);
> +            if (It == BMap.end())
> +              insertAttrExprs(Cpvd, Analyzer);
> +          }
> +        }
> +        break;
> +      }
> +      case attr::AcquiredAfter: {
> +        auto *A = cast<AcquiredAfterAttr>(At);
> +
> +        // Read exprs from the attribute, and add them to BeforeVect.
> +        for (const auto *Arg : A->args()) {
> +          CapabilityExpr Cp =
> +            Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);
> +          if (const ValueDecl *ArgVd = Cp.valueDecl()) {
> +            // Get entry for mutex listed in attribute
> +            BeforeInfo* ArgInfo;
> +            auto It = BMap.find(ArgVd);
> +            if (It == BMap.end())
> +              ArgInfo = insertAttrExprs(ArgVd, Analyzer);
> +            else
> +              ArgInfo = &It->second;
> +
> +            // Create a new BeforeVect if necessary.
> +            BeforeVect* ArgBv = ArgInfo->Vect.get();
> +            if (!ArgBv) {
> +              ArgBv = new BeforeVect;
> +              ArgInfo->Vect.reset(ArgBv);
> +            }
> +            ArgBv->push_back(Vd);
> +          }
> +        }
> +        break;
> +      }
> +      default:
> +        break;
> +    }
> +  }
> +
> +  return Info;
> +}
> +
> +
> +/// Return true if any mutexes in FSet are in the acquired_before set of Vd.
> +void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd,
> +                                 const FactSet& FSet,
> +                                 ThreadSafetyAnalyzer& Analyzer,
> +                                 SourceLocation Loc, StringRef CapKind) {
> +  SmallVector<BeforeInfo*, 8> InfoVect;
> +
> +  // Do a depth-first traversal of Vd.
> +  // Return true if there are cycles.
> +  std::function<bool (const ValueDecl*)> traverse = [&](const ValueDecl* Vd) {
> +    if (!Vd)
> +      return false;
> +
> +    BeforeSet::BeforeInfo* Info;
> +    auto It = BMap.find(Vd);
> +    if (It == BMap.end())
> +      Info = insertAttrExprs(Vd, Analyzer);
> +    else
> +      Info = &It->second;
> +
> +    if (Info->Visited == 1)
> +      return true;
> +
> +    if (Info->Visited == 2)
> +      return false;
> +
> +    BeforeVect* Bv = Info->Vect.get();
> +    if (!Bv)
> +      return false;
> +
> +    InfoVect.push_back(Info);
> +    Info->Visited = 1;
> +    for (auto *Vdb : *Bv) {
> +      // Exclude mutexes in our immediate before set.
> +      if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {
> +        StringRef L1 = StartVd->getName();
> +        StringRef L2 = Vdb->getName();
> +        Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc);
> +      }
> +      // Transitively search other before sets, and warn on cycles.
> +      if (traverse(Vdb)) {
> +        if (CycMap.find(Vd) == CycMap.end()) {
> +          CycMap.insert(std::make_pair(Vd, true));
> +          StringRef L1 = Vd->getName();
> +          Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->getLocation());
> +        }
> +      }
> +    }
> +    Info->Visited = 2;
> +    return false;
> +  };
> +
> +  traverse(StartVd);
> +
> +  for (auto* Info : InfoVect)
> +    Info->Visited = 0;
> +}
> +
> +
> +
>  /// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs.
>  static const ValueDecl *getValueDecl(const Expr *Exp) {
>    if (const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))
> @@ -1020,7 +1200,13 @@ void ThreadSafetyAnalyzer::addLock(FactS
>      }
>    }
>  
> -  // FIXME: deal with acquired before/after annotations.
> +  // Check before/after constraints
> +  if (Handler.issueBetaWarnings() &&
> +      !Entry->asserted() && !Entry->declared()) {
> +    GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *this,
> +                                      Entry->loc(), DiagKind);
> +  }
> +
>    // FIXME: Don't always warn when we have support for reentrant locks.
>    if (FSet.findLock(FactMan, *Entry)) {
>      if (!Entry->asserted())
> @@ -1979,14 +2165,16 @@ void ThreadSafetyAnalyzer::runAnalysis(A
>      }
>  
>      // FIXME -- Loc can be wrong here.
> -    for (const auto &Mu : ExclusiveLocksToAdd)
> -      addLock(InitialLockset,
> -              llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc),
> -              CapDiagKind, true);
> -    for (const auto &Mu : SharedLocksToAdd)
> -      addLock(InitialLockset,
> -              llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc),
> -              CapDiagKind, true);
> +    for (const auto &Mu : ExclusiveLocksToAdd) {
> +      auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc);
> +      Entry->setDeclared(true);
> +      addLock(InitialLockset, std::move(Entry), CapDiagKind, true);
> +    }
> +    for (const auto &Mu : SharedLocksToAdd) {
> +      auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc);
> +      Entry->setDeclared(true);
> +      addLock(InitialLockset, std::move(Entry), CapDiagKind, true);
> +    }
>    }
>  
>    for (const auto *CurrBlock : *SortedGraph) {
> @@ -2180,11 +2368,20 @@ void ThreadSafetyAnalyzer::runAnalysis(A
>  /// at the end of each block, and issue warnings for thread safety violations.
>  /// Each block in the CFG is traversed exactly once.
>  void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
> -                             ThreadSafetyHandler &Handler) {
> -  ThreadSafetyAnalyzer Analyzer(Handler);
> +                             ThreadSafetyHandler &Handler,
> +                             BeforeSet **BSet) {
> +  if (!*BSet)
> +    *BSet = new BeforeSet;
> +  ThreadSafetyAnalyzer Analyzer(Handler, *BSet);
>    Analyzer.runAnalysis(AC);
>  }
>  
> +
> +void threadSafetyCleanup(BeforeSet* Cache) {
> +  delete Cache;
> +}
> +
> +
>  /// \brief Helper function that returns a LockKind required for the given level
>  /// of access.
>  LockKind getLockKindFromAccessKind(AccessKind AK) {
>
> Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
> +++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Tue Feb  3 12:17:48 2015
> @@ -1679,6 +1679,22 @@ class ThreadSafetyReporter : public clan
>      Warnings.push_back(DelayedDiag(Warning, getNotes()));
>    }
>  
> +
> +  virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name,
> +                                        Name L2Name, SourceLocation Loc)
> +      override {
> +    PartialDiagnosticAt Warning(Loc,
> +      S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name);
> +    Warnings.push_back(DelayedDiag(Warning, getNotes()));
> +  }
> +
> +  virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc)
> +      override {
> +    PartialDiagnosticAt Warning(Loc,
> +      S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name);
> +    Warnings.push_back(DelayedDiag(Warning, getNotes()));
> +  }
> +
>    void enterFunction(const FunctionDecl* FD) override {
>      CurrentFunction = FD;
>    }
> @@ -1704,7 +1720,7 @@ class ConsumedWarningsHandler : public C
>    DiagList Warnings;
>    
>  public:
> -  
> +
>    ConsumedWarningsHandler(Sema &S) : S(S) {}
>  
>    void emitDiagnostics() override {
> @@ -1981,7 +1997,8 @@ AnalysisBasedWarnings::IssueWarnings(sem
>      if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getLocStart()))
>        Reporter.setVerbose(true);
>  
> -    threadSafety::runThreadSafetyAnalysis(AC, Reporter);
> +    threadSafety::runThreadSafetyAnalysis(AC, Reporter,
> +                                          &S.ThreadSafetyDeclCache);
>      Reporter.emitDiagnostics();
>    }
>  
>
> Modified: cfe/trunk/lib/Sema/Sema.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/Sema.cpp (original)
> +++ cfe/trunk/lib/Sema/Sema.cpp Tue Feb  3 12:17:48 2015
> @@ -102,7 +102,7 @@ Sema::Sema(Preprocessor &pp, ASTContext
>      AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
>      NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
>      CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
> -    TyposCorrected(0), AnalysisWarnings(*this),
> +    TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
>      VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
>      Ident_super(nullptr), Ident___float128(nullptr)
>  {
> @@ -243,6 +243,8 @@ Sema::~Sema() {
>    if (isMultiplexExternalSource)
>      delete ExternalSource;
>  
> +  threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);
> +
>    // Destroys data sharing attributes stack for OpenMP
>    DestroyDataSharingAttributesStack();
>  
>
> Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=227997&r1=227996&r2=227997&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
> +++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Tue Feb  3 12:17:48 2015
> @@ -4835,7 +4835,7 @@ public:
>      read2(10, *foosp);        // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
>      destroy(mymove(*foosp));  // expected-warning {{reading the value pointed to by 'foosp' requires holding mutex 'mu'}}
>  
> -    // TODO -- these requires better smart pointer handling.
> +    // TODO -- these require better smart pointer handling.
>      copy(*foosp.get());
>      write1(*foosp.get());
>      write2(10, *foosp.get());
> @@ -4848,3 +4848,213 @@ public:
>  
>  }  // end namespace PassByRefTest
>  
> +
> +namespace AcquiredBeforeAfterText {
> +
> +class Foo {
> +  Mutex mu1 ACQUIRED_BEFORE(mu2, mu3);
> +  Mutex mu2;
> +  Mutex mu3;
> +
> +  void test1() {
> +    mu1.Lock();
> +    mu2.Lock();
> +    mu3.Lock();
> +
> +    mu3.Unlock();
> +    mu2.Unlock();
> +    mu1.Unlock();
> +  }
> +
> +  void test2() {
> +    mu2.Lock();
> +    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}
> +    mu1.Unlock();
> +    mu2.Unlock();
> +  }
> +
> +  void test3() {
> +    mu3.Lock();
> +    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}
> +    mu1.Unlock();
> +    mu3.Unlock();
> +  }
> +
> +  void test4() EXCLUSIVE_LOCKS_REQUIRED(mu1) {
> +    mu2.Lock();
> +    mu2.Unlock();
> +  }
> +
> +  void test5() EXCLUSIVE_LOCKS_REQUIRED(mu2) {
> +    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}
> +    mu1.Unlock();
> +  }
> +
> +  void test6() EXCLUSIVE_LOCKS_REQUIRED(mu2) {
> +    mu1.AssertHeld();
> +  }
> +
> +  void test7() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2, mu3) { }
> +
> +  void test8() EXCLUSIVE_LOCKS_REQUIRED(mu3, mu2, mu1) { }
> +};
> +
> +
> +class Foo2 {
> +  Mutex mu1;
> +  Mutex mu2 ACQUIRED_AFTER(mu1);
> +  Mutex mu3 ACQUIRED_AFTER(mu1);
> +
> +  void test1() {
> +    mu1.Lock();
> +    mu2.Lock();
> +    mu3.Lock();
> +
> +    mu3.Unlock();
> +    mu2.Unlock();
> +    mu1.Unlock();
> +  }
> +
> +  void test2() {
> +    mu2.Lock();
> +    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu2'}}
> +    mu1.Unlock();
> +    mu2.Unlock();
> +  }
> +
> +  void test3() {
> +    mu3.Lock();
> +    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}
> +    mu1.Unlock();
> +    mu3.Unlock();
> +  }
> +};
> +
> +
> +class Foo3 {
> +  Mutex mu1 ACQUIRED_BEFORE(mu2);
> +  Mutex mu2;
> +  Mutex mu3 ACQUIRED_AFTER(mu2) ACQUIRED_BEFORE(mu4);
> +  Mutex mu4;
> +
> +  void test1() {
> +    mu1.Lock();
> +    mu2.Lock();
> +    mu3.Lock();
> +    mu4.Lock();
> +
> +    mu4.Unlock();
> +    mu3.Unlock();
> +    mu2.Unlock();
> +    mu1.Unlock();
> +  }
> +
> +  void test2() {
> +    mu4.Lock();
> +    mu2.Lock();     // expected-warning {{mutex 'mu2' must be acquired before 'mu4'}}
> +
> +    mu2.Unlock();
> +    mu4.Unlock();
> +  }
> +
> +  void test3() {
> +    mu4.Lock();
> +    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu4'}}
> +
> +    mu1.Unlock();
> +    mu4.Unlock();
> +  }
> +
> +  void test4() {
> +    mu3.Lock();
> +    mu1.Lock();     // expected-warning {{mutex 'mu1' must be acquired before 'mu3'}}
> +
> +    mu1.Unlock();
> +    mu3.Unlock();
> +  }
> +};
> +
> +
> +// Test transitive DAG traversal with AFTER
> +class Foo4 {
> +  Mutex mu1;
> +  Mutex mu2 ACQUIRED_AFTER(mu1);
> +  Mutex mu3 ACQUIRED_AFTER(mu1);
> +  Mutex mu4 ACQUIRED_AFTER(mu2, mu3);
> +  Mutex mu5 ACQUIRED_AFTER(mu4);
> +  Mutex mu6 ACQUIRED_AFTER(mu4);
> +  Mutex mu7 ACQUIRED_AFTER(mu5, mu6);
> +  Mutex mu8 ACQUIRED_AFTER(mu7);
> +
> +  void test() {
> +    mu8.Lock();
> +    mu1.Lock();    // expected-warning {{mutex 'mu1' must be acquired before 'mu8'}}
> +    mu1.Unlock();
> +    mu8.Unlock();
> +  }
> +};
> +
> +
> +// Test transitive DAG traversal with BEFORE
> +class Foo5 {
> +  Mutex mu1 ACQUIRED_BEFORE(mu2, mu3);
> +  Mutex mu2 ACQUIRED_BEFORE(mu4);
> +  Mutex mu3 ACQUIRED_BEFORE(mu4);
> +  Mutex mu4 ACQUIRED_BEFORE(mu5, mu6);
> +  Mutex mu5 ACQUIRED_BEFORE(mu7);
> +  Mutex mu6 ACQUIRED_BEFORE(mu7);
> +  Mutex mu7 ACQUIRED_BEFORE(mu8);
> +  Mutex mu8;
> +
> +  void test() {
> +    mu8.Lock();
> +    mu1.Lock();  // expected-warning {{mutex 'mu1' must be acquired before 'mu8'}}
> +    mu1.Unlock();
> +    mu8.Unlock();
> +  }
> +};
> +
> +
> +class Foo6 {
> +  Mutex mu1 ACQUIRED_AFTER(mu3);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu1'}}
> +  Mutex mu2 ACQUIRED_AFTER(mu1);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu2'}}
> +  Mutex mu3 ACQUIRED_AFTER(mu2);     // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu3'}}
> +
> +  Mutex mu_b ACQUIRED_BEFORE(mu_b);  // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu_b'}}
> +  Mutex mu_a ACQUIRED_AFTER(mu_a);   // expected-warning {{Cycle in acquired_before/after dependencies, starting with 'mu_a'}}
> +
> +  void test0() {
> +    mu_a.Lock();
> +    mu_b.Lock();
> +    mu_b.Unlock();
> +    mu_a.Unlock();
> +  }
> +
> +  void test1a() {
> +    mu1.Lock();
> +    mu1.Unlock();
> +  }
> +
> +  void test1b() {
> +    mu1.Lock();
> +    mu_a.Lock();
> +    mu_b.Lock();
> +    mu_b.Unlock();
> +    mu_a.Unlock();
> +    mu1.Unlock();
> +  }
> +
> +  void test() {
> +    mu2.Lock();
> +    mu2.Unlock();
> +  }
> +
> +  void test3() {
> +    mu3.Lock();
> +    mu3.Unlock();
> +  }
> +};
> +
> +
> +}  // end namespace AcquiredBeforeAfterTest
> +
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list