diff options
author | DeLesley Hutchins <delesley@google.com> | 2015-02-04 21:16:17 +0000 |
---|---|---|
committer | DeLesley Hutchins <delesley@google.com> | 2015-02-04 21:16:17 +0000 |
commit | 3c355aa24d93e0ebb65ba0631d14169ddab0cdfb (patch) | |
tree | 1418fb691614e2c73d040b4d25d71a51d8abdd15 /clang/lib/Analysis | |
parent | 52a25237d894fd5736a90f11df2c5c9391d13fd5 (diff) | |
download | bcm5719-llvm-3c355aa24d93e0ebb65ba0631d14169ddab0cdfb.tar.gz bcm5719-llvm-3c355aa24d93e0ebb65ba0631d14169ddab0cdfb.zip |
Thread Safety Analysis: support adopting of locks, as implemented in
std::lock_guard. If EXCLUSIVE_LOCKS_REQUIRED is placed on the constructor of
a SCOPED_LOCKABLE class, then that constructor is assumed to adopt the lock;
e.g. the lock must be held on construction, and will be released on destruction.
llvm-svn: 228194
Diffstat (limited to 'clang/lib/Analysis')
-rw-r--r-- | clang/lib/Analysis/ThreadSafety.cpp | 35 |
1 files changed, 24 insertions, 11 deletions
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index b5d87d2e651..37819a74d5d 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -1690,8 +1690,19 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { SourceLocation Loc = Exp->getExprLoc(); CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd; CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove; + CapExprSet ScopedExclusiveReqs, ScopedSharedReqs; StringRef CapDiagKind = "mutex"; + // Figure out if we're calling the constructor of scoped lockable class + bool isScopedVar = false; + if (VD) { + if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) { + const CXXRecordDecl* PD = CD->getParent(); + if (PD && PD->hasAttr<ScopedLockableAttr>()) + isScopedVar = true; + } + } + for(Attr *Atconst : D->attrs()) { Attr* At = const_cast<Attr*>(Atconst); switch (At->getKind()) { @@ -1751,10 +1762,17 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { case attr::RequiresCapability: { RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At); - for (auto *Arg : A->args()) + for (auto *Arg : A->args()) { warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg, POK_FunctionCall, ClassifyDiagnostic(A), Exp->getExprLoc()); + // use for adopting a lock + if (isScopedVar) { + Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs + : ScopedExclusiveReqs, + A, Exp, D, VD); + } + } break; } @@ -1771,16 +1789,6 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { } } - // Figure out if we're calling the constructor of scoped lockable class - bool isScopedVar = false; - if (VD) { - if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) { - const CXXRecordDecl* PD = CD->getParent(); - if (PD && PD->hasAttr<ScopedLockableAttr>()) - isScopedVar = true; - } - } - // Add locks. for (const auto &M : ExclusiveLocksToAdd) Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>( @@ -1797,6 +1805,11 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation()); // FIXME: does this store a pointer to DRE? CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr); + + std::copy(ScopedExclusiveReqs.begin(), ScopedExclusiveReqs.end(), + std::back_inserter(ExclusiveLocksToAdd)); + std::copy(ScopedSharedReqs.begin(), ScopedSharedReqs.end(), + std::back_inserter(SharedLocksToAdd)); Analyzer->addLock(FSet, llvm::make_unique<ScopedLockableFactEntry>( Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd), |