diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis')
9 files changed, 383 insertions, 168 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp index be66f32..4e623c8 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -530,14 +530,14 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD, return BV; } -std::pair<AnalysisDeclContext::referenced_decls_iterator, - AnalysisDeclContext::referenced_decls_iterator> +llvm::iterator_range<AnalysisDeclContext::referenced_decls_iterator> AnalysisDeclContext::getReferencedBlockVars(const BlockDecl *BD) { if (!ReferencedBlockVars) ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>(); - DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); - return std::make_pair(V->begin(), V->end()); + const DeclVec *V = + LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); + return llvm::make_range(V->begin(), V->end()); } ManagedAnalysis *&AnalysisDeclContext::getAnalysisImpl(const void *tag) { diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp index d9073aa..2744c5f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp @@ -156,7 +156,7 @@ public: return !(*this == rhs); } - LLVM_EXPLICIT operator bool() const { + explicit operator bool() const { return *this != const_iterator(); } @@ -203,9 +203,9 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) { return D; } -/// BlockScopePosPair - Structure for specifying position in CFG during its -/// build process. It consists of CFGBlock that specifies position in CFG graph -/// and LocalScope::const_iterator that specifies position in LocalScope graph. +/// Structure for specifying position in CFG during its build process. It +/// consists of CFGBlock that specifies position in CFG and +/// LocalScope::const_iterator that specifies position in LocalScope graph. struct BlockScopePosPair { BlockScopePosPair() : block(nullptr) {} BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos) @@ -841,12 +841,12 @@ private: // must be false. llvm::APSInt IntVal; if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) { - if (IntVal.getBoolValue() == false) { + if (!IntVal.getBoolValue()) { return TryResult(false); } } if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) { - if (IntVal.getBoolValue() == false) { + if (!IntVal.getBoolValue()) { return TryResult(false); } } @@ -3950,9 +3950,8 @@ public: } } } - - virtual ~StmtPrinterHelper() {} + ~StmtPrinterHelper() override {} const LangOptions &getLangOpts() const { return LangOpts; } void setBlockID(signed i) { currentBlock = i; } diff --git a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp index 2b2da2c..fa985ee 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp @@ -946,10 +946,9 @@ void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) { namespace clang { namespace consumed { -void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, - ConsumedStateMap *ThenStates, - ConsumedStateMap *ElseStates) { - +static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test, + ConsumedStateMap *ThenStates, + ConsumedStateMap *ElseStates) { ConsumedState VarState = ThenStates->getState(Test.Var); if (VarState == CS_Unknown) { @@ -964,9 +963,9 @@ void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, } } -void splitVarStateForIfBinOp(const PropagationInfo &PInfo, - ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) { - +static void splitVarStateForIfBinOp(const PropagationInfo &PInfo, + ConsumedStateMap *ThenStates, + ConsumedStateMap *ElseStates) { const VarTestResult <est = PInfo.getLTest(), &RTest = PInfo.getRTest(); @@ -1443,7 +1442,7 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { CurrStates, WarningsHandler); - if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock)) + if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI)) BlockInfo.discardInfo(*SI); } else { BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken); diff --git a/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp index 662166c..0948bc0 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp @@ -256,16 +256,17 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, // Methods on ArgType. //===----------------------------------------------------------------------===// -bool ArgType::matchesType(ASTContext &C, QualType argTy) const { +clang::analyze_format_string::ArgType::MatchKind +ArgType::matchesType(ASTContext &C, QualType argTy) const { if (Ptr) { // It has to be a pointer. const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; // We cannot write through a const qualified pointer. if (PT->getPointeeType().isConstQualified()) - return false; + return NoMatch; argTy = PT->getPointeeType(); } @@ -275,8 +276,8 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { llvm_unreachable("ArgType must be valid"); case UnknownTy: - return true; - + return Match; + case AnyCharTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); @@ -289,18 +290,18 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Char_U: - return true; + return Match; } - return false; + return NoMatch; } - + case SpecificTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); argTy = C.getCanonicalType(argTy).getUnqualifiedType(); if (T == argTy) - return true; + return Match; // Check for "compatible types". if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) switch (BT->getKind()) { @@ -309,32 +310,33 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::Char_S: case BuiltinType::SChar: case BuiltinType::Char_U: - case BuiltinType::UChar: - return T == C.UnsignedCharTy || T == C.SignedCharTy; + case BuiltinType::UChar: + return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match + : NoMatch; case BuiltinType::Short: - return T == C.UnsignedShortTy; + return T == C.UnsignedShortTy ? Match : NoMatch; case BuiltinType::UShort: - return T == C.ShortTy; + return T == C.ShortTy ? Match : NoMatch; case BuiltinType::Int: - return T == C.UnsignedIntTy; + return T == C.UnsignedIntTy ? Match : NoMatch; case BuiltinType::UInt: - return T == C.IntTy; + return T == C.IntTy ? Match : NoMatch; case BuiltinType::Long: - return T == C.UnsignedLongTy; + return T == C.UnsignedLongTy ? Match : NoMatch; case BuiltinType::ULong: - return T == C.LongTy; + return T == C.LongTy ? Match : NoMatch; case BuiltinType::LongLong: - return T == C.UnsignedLongLongTy; + return T == C.UnsignedLongLongTy ? Match : NoMatch; case BuiltinType::ULongLong: - return T == C.LongLongTy; + return T == C.LongLongTy ? Match : NoMatch; } - return false; + return NoMatch; } case CStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; QualType pointeeTy = PT->getPointeeType(); if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) switch (BT->getKind()) { @@ -343,50 +345,56 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: - return true; + return Match; default: break; } - return false; + return NoMatch; } case WCStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; QualType pointeeTy = C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); - return pointeeTy == C.getWideCharType(); + return pointeeTy == C.getWideCharType() ? Match : NoMatch; } - + case WIntTy: { - + QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; - + QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType(); PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); - + // If the promoted argument is the corresponding signed type of the // wint_t type, then it should match. if (PromoArg->hasSignedIntegerRepresentation() && C.getCorrespondingUnsignedType(PromoArg) == WInt) - return true; + return Match; - return WInt == PromoArg; + return WInt == PromoArg ? Match : NoMatch; } case CPointerTy: - return argTy->isPointerType() || argTy->isObjCObjectPointerType() || - argTy->isBlockPointerType() || argTy->isNullPtrType(); + if (argTy->isVoidPointerType()) { + return Match; + } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() || + argTy->isBlockPointerType() || argTy->isNullPtrType()) { + return NoMatchPedantic; + } else { + return NoMatch; + } case ObjCPointerTy: { if (argTy->getAs<ObjCObjectPointerType>() || argTy->getAs<BlockPointerType>()) - return true; - + return Match; + // Handle implicit toll-free bridging. if (const PointerType *PT = argTy->getAs<PointerType>()) { // Things such as CFTypeRef are really just opaque pointers @@ -395,9 +403,9 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { // structs can be toll-free bridged, we just accept them all. QualType pointee = PT->getPointeeType(); if (pointee->getAsStructureType() || pointee->isVoidType()) - return true; + return Match; } - return false; + return NoMatch; } } @@ -791,7 +799,8 @@ bool FormatSpecifier::hasStandardLengthModifier() const { llvm_unreachable("Invalid LengthModifier Kind!"); } -bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) const { +bool FormatSpecifier::hasStandardConversionSpecifier( + const LangOptions &LangOpt) const { switch (CS.getKind()) { case ConversionSpecifier::cArg: case ConversionSpecifier::dArg: diff --git a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp index 86b679c..0ab1580 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp @@ -356,11 +356,8 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { } void TransferFunctions::VisitBlockExpr(BlockExpr *BE) { - AnalysisDeclContext::referenced_decls_iterator I, E; - std::tie(I, E) = - LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl()); - for ( ; I != E ; ++I) { - const VarDecl *VD = *I; + for (const VarDecl *VD : + LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl())) { if (isAlwaysAlive(VD)) continue; val.liveDecls = LV.DSetFact.add(val.liveDecls, VD); diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp index f45d6e7..e2c6ab5 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp @@ -44,14 +44,13 @@ #include <sstream> #include <utility> #include <vector> - - -namespace clang { -namespace threadSafety { +using namespace clang; +using namespace threadSafety; // Key method definition ThreadSafetyHandler::~ThreadSafetyHandler() {} +namespace { class TILPrinter : public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {}; @@ -69,7 +68,6 @@ static void warnInvalidLock(ThreadSafetyHandler &Handler, Handler.handleInvalidLockExp(Kind, Loc); } - /// \brief A set of CapabilityInfo objects, which are compiled from the /// requires attributes on a function. class CapExprSet : public SmallVector<CapabilityExpr, 4> { @@ -101,17 +99,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 +234,61 @@ 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; +} // namespace + +namespace clang { +namespace threadSafety { +class BeforeSet { +private: + typedef SmallVector<const ValueDecl*, 4> BeforeVect; + + struct BeforeInfo { + BeforeInfo() : Vect(nullptr), Visited(false) { } + BeforeInfo(BeforeInfo &&O) + : Vect(std::move(O.Vect)), Visited(O.Visited) + {} + + 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; +}; +} // end namespace threadSafety +} // end namespace clang +namespace { typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext; class LocalVariableMap; @@ -853,6 +903,7 @@ public: /// \brief Class which implements the core thread safety analysis routines. class ThreadSafetyAnalyzer { friend class BuildLockset; + friend class threadSafety::BeforeSet; llvm::BumpPtrAllocator Bpa; threadSafety::til::MemRegionRef Arena; @@ -864,9 +915,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); @@ -906,6 +959,134 @@ public: void runAnalysis(AnalysisDeclContext &AC); }; +} // namespace + +/// 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; + + for (Attr* At : Vd->attrs()) { + 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) { @@ -921,6 +1102,7 @@ static const ValueDecl *getValueDecl(const Expr *Exp) { return nullptr; } +namespace { template <typename Ty> class has_arg_iterator_range { typedef char yes[1]; @@ -935,6 +1117,7 @@ class has_arg_iterator_range { public: static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes); }; +} // namespace static StringRef ClassifyDiagnostic(const CapabilityAttr *A) { return A->getName(); @@ -1020,7 +1203,13 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, } } - // 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()) @@ -1119,8 +1308,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, } } - -bool getStaticBooleanValue(Expr* E, bool& TCond) { +static bool getStaticBooleanValue(Expr *E, bool &TCond) { if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) { TCond = false; return true; @@ -1230,7 +1418,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, CapExprSet SharedLocksToAdd; // If the condition is a call to a Trylock function, then grab the attributes - for (auto *Attr : FunDecl->getAttrs()) { + for (auto *Attr : FunDecl->attrs()) { switch (Attr->getKind()) { case attr::ExclusiveTrylockFunction: { ExclusiveTrylockFunctionAttr *A = @@ -1265,6 +1453,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, CapDiagKind); } +namespace { /// \brief We use this class to visit different types of expressions in /// CFGBlocks, and build up the lockset. /// An expression may cause us to add or remove locks from the lockset, or else @@ -1308,7 +1497,7 @@ public: void VisitCXXConstructExpr(CXXConstructExpr *Exp); void VisitDeclStmt(DeclStmt *S); }; - +} // namespace /// \brief Warn if the LSet does not contain a lock sufficient to protect access /// of at least the passed in AccessKind. @@ -1500,13 +1689,23 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK, /// void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { SourceLocation Loc = Exp->getExprLoc(); - const AttrVec &ArgAttrs = D->getAttrs(); CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd; CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove; + CapExprSet ScopedExclusiveReqs, ScopedSharedReqs; StringRef CapDiagKind = "mutex"; - for(unsigned i = 0; i < ArgAttrs.size(); ++i) { - Attr *At = const_cast<Attr*>(ArgAttrs[i]); + // 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()) { // When we encounter a lock function, we need to add the lock to our // lockset. @@ -1564,10 +1763,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; } @@ -1584,16 +1790,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>( @@ -1611,9 +1807,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { // FIXME: does this store a pointer to DRE? CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr); - CapExprSet UnderlyingMutexes(ExclusiveLocksToAdd); - std::copy(SharedLocksToAdd.begin(), SharedLocksToAdd.end(), - std::back_inserter(UnderlyingMutexes)); + 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), @@ -1863,7 +2060,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, // Return true if block B never continues to its successors. -inline bool neverReturns(const CFGBlock* B) { +static bool neverReturns(const CFGBlock *B) { if (B->hasNoReturnElement()) return true; if (B->empty()) @@ -1940,14 +2137,13 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { if (!SortedGraph->empty() && D->hasAttrs()) { const CFGBlock *FirstBlock = *SortedGraph->begin(); FactSet &InitialLockset = BlockInfo[FirstBlock->getBlockID()].EntrySet; - const AttrVec &ArgAttrs = D->getAttrs(); CapExprSet ExclusiveLocksToAdd; CapExprSet SharedLocksToAdd; StringRef CapDiagKind = "mutex"; SourceLocation Loc = D->getLocation(); - for (const auto *Attr : ArgAttrs) { + for (const auto *Attr : D->attrs()) { Loc = Attr->getLocation(); if (const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) { getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, @@ -1979,14 +2175,16 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } // 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) { @@ -2179,15 +2377,20 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { /// We traverse the blocks in the CFG, compute the set of mutexes that are held /// 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); +void threadSafety::runThreadSafetyAnalysis(AnalysisDeclContext &AC, + ThreadSafetyHandler &Handler, + BeforeSet **BSet) { + if (!*BSet) + *BSet = new BeforeSet; + ThreadSafetyAnalyzer Analyzer(Handler, *BSet); Analyzer.runAnalysis(AC); } +void threadSafety::threadSafetyCleanup(BeforeSet *Cache) { delete Cache; } + /// \brief Helper function that returns a LockKind required for the given level /// of access. -LockKind getLockKindFromAccessKind(AccessKind AK) { +LockKind threadSafety::getLockKindFromAccessKind(AccessKind AK) { switch (AK) { case AK_Read : return LK_Shared; @@ -2196,5 +2399,3 @@ LockKind getLockKindFromAccessKind(AccessKind AK) { } llvm_unreachable("Unknown AccessKind"); } - -}} // end namespace clang::threadSafety diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp index 563e059..d4b1ce2 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -31,13 +31,11 @@ #include <algorithm> #include <climits> #include <vector> - - -namespace clang { -namespace threadSafety { +using namespace clang; +using namespace threadSafety; // From ThreadSafetyUtil.h -std::string getSourceLiteralString(const clang::Expr *CE) { +std::string threadSafety::getSourceLiteralString(const clang::Expr *CE) { switch (CE->getStmtClass()) { case Stmt::IntegerLiteralClass: return cast<IntegerLiteral>(CE)->getValue().toString(10, true); @@ -59,18 +57,13 @@ std::string getSourceLiteralString(const clang::Expr *CE) { } } -namespace til { - // Return true if E is a variable that points to an incomplete Phi node. -static bool isIncompletePhi(const SExpr *E) { - if (const auto *Ph = dyn_cast<Phi>(E)) - return Ph->status() == Phi::PH_Incomplete; +static bool isIncompletePhi(const til::SExpr *E) { + if (const auto *Ph = dyn_cast<til::Phi>(E)) + return Ph->status() == til::Phi::PH_Incomplete; return false; } -} // end namespace til - - typedef SExprBuilder::CallingContext CallingContext; @@ -87,9 +80,7 @@ til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) { return Scfg; } - - -inline bool isCalleeArrow(const Expr *E) { +static bool isCalleeArrow(const Expr *E) { const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts()); return ME ? ME->isArrow() : false; } @@ -313,8 +304,7 @@ til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE, return SelfVar; } - -const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) { +static const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) { if (auto *V = dyn_cast<til::Variable>(E)) return V->clangDecl(); if (auto *Ph = dyn_cast<til::Phi>(E)) @@ -326,7 +316,7 @@ const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) { return 0; } -bool hasCppPointerType(const til::SExpr *E) { +static bool hasCppPointerType(const til::SExpr *E) { auto *VD = getValueDeclFromSExpr(E); if (VD && VD->getType()->isPointerType()) return true; @@ -336,9 +326,8 @@ bool hasCppPointerType(const til::SExpr *E) { return false; } - // Grab the very first declaration of virtual method D -const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) { +static const CXXMethodDecl *getFirstVirtualDecl(const CXXMethodDecl *D) { while (true) { D = D->getCanonicalDecl(); CXXMethodDecl::method_iterator I = D->begin_overridden_methods(), @@ -663,7 +652,7 @@ til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) { // if E is a til::Variable, update its clangDecl. -inline void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) { +static void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) { if (!E) return; if (til::Variable *V = dyn_cast<til::Variable>(E)) { @@ -986,8 +975,3 @@ void printSCFG(CFGWalker &Walker) { TILPrinter::print(Scfg, llvm::errs()); } */ - - -} // end namespace threadSafety - -} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp index ebe374e..2923f7e6 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp @@ -9,13 +9,11 @@ #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" +using namespace clang; +using namespace threadSafety; +using namespace til; -namespace clang { -namespace threadSafety { -namespace til { - - -StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) { +StringRef til::getUnaryOpcodeString(TIL_UnaryOpcode Op) { switch (Op) { case UOP_Minus: return "-"; case UOP_BitNot: return "~"; @@ -24,8 +22,7 @@ StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) { return ""; } - -StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) { +StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) { switch (Op) { case BOP_Mul: return "*"; case BOP_Div: return "/"; @@ -82,7 +79,7 @@ void BasicBlock::reservePredecessors(unsigned NumPreds) { // If E is a variable, then trace back through any aliases or redundant // Phi nodes to find the canonical definition. -const SExpr *getCanonicalVal(const SExpr *E) { +const SExpr *til::getCanonicalVal(const SExpr *E) { while (true) { if (auto *V = dyn_cast<Variable>(E)) { if (V->kind() == Variable::VK_Let) { @@ -105,7 +102,7 @@ const SExpr *getCanonicalVal(const SExpr *E) { // If E is a variable, then trace back through any aliases or redundant // Phi nodes to find the canonical definition. // The non-const version will simplify incomplete Phi nodes. -SExpr *simplifyToCanonicalVal(SExpr *E) { +SExpr *til::simplifyToCanonicalVal(SExpr *E) { while (true) { if (auto *V = dyn_cast<Variable>(E)) { if (V->kind() != Variable::VK_Let) @@ -135,7 +132,7 @@ SExpr *simplifyToCanonicalVal(SExpr *E) { // Trace the arguments of an incomplete Phi node to see if they have the same // canonical definition. If so, mark the Phi node as redundant. // getCanonicalVal() will recursively call simplifyIncompletePhi(). -void simplifyIncompleteArg(til::Phi *Ph) { +void til::simplifyIncompleteArg(til::Phi *Ph) { assert(Ph && Ph->status() == Phi::PH_Incomplete); // eliminate infinite recursion -- assume that this node is not redundant. @@ -337,7 +334,3 @@ void SCFG::computeNormalForm() { computeNodeID(Block, &BasicBlock::PostDominatorNode); } } - -} // end namespace til -} // end namespace threadSafety -} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp index 61a2592..f2f7919 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/UninitializedValues.h" @@ -35,9 +36,9 @@ using namespace clang; static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && !vd->isExceptionVariable() && !vd->isInitCapture() && - vd->getDeclContext() == dc) { + !vd->isImplicit() && vd->getDeclContext() == dc) { QualType ty = vd->getType(); - return ty->isScalarType() || ty->isVectorType(); + return ty->isScalarType() || ty->isVectorType() || ty->isRecordType(); } return false; } @@ -347,6 +348,7 @@ public: } static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) { + if (VD->getType()->isRecordType()) return nullptr; if (Expr *Init = VD->getInit()) { const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init)); @@ -376,10 +378,26 @@ void ClassifyRefs::classify(const Expr *E, Class C) { return; } + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) { + if (!VD->isStaticDataMember()) + classify(ME->getBase(), C); + } + return; + } + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - if (BO->getOpcode() == BO_Comma) + switch (BO->getOpcode()) { + case BO_PtrMemD: + case BO_PtrMemI: + classify(BO->getLHS(), C); + return; + case BO_Comma: classify(BO->getRHS(), C); - return; + return; + default: + return; + } } FindVarResult Var = findVar(E, DC); @@ -404,7 +422,7 @@ void ClassifyRefs::VisitBinaryOperator(BinaryOperator *BO) { // use. if (BO->isCompoundAssignmentOp()) classify(BO->getLHS(), Use); - else if (BO->getOpcode() == BO_Assign) + else if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma) classify(BO->getLHS(), Ignore); } @@ -415,25 +433,40 @@ void ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) { classify(UO->getSubExpr(), Use); } +static bool isPointerToConst(const QualType &QT) { + return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified(); +} + void ClassifyRefs::VisitCallExpr(CallExpr *CE) { // Classify arguments to std::move as used. if (CE->getNumArgs() == 1) { if (FunctionDecl *FD = CE->getDirectCallee()) { if (FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move")) { - classify(CE->getArg(0), Use); + // RecordTypes are handled in SemaDeclCXX.cpp. + if (!CE->getArg(0)->getType()->isRecordType()) + classify(CE->getArg(0), Use); return; } } } - // If a value is passed by const reference to a function, we should not assume - // that it is initialized by the call, and we conservatively do not assume - // that it is used. + // If a value is passed by const pointer or by const reference to a function, + // we should not assume that it is initialized by the call, and we + // conservatively do not assume that it is used. for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) - if ((*I)->getType().isConstQualified() && (*I)->isGLValue()) - classify(*I, Ignore); + I != E; ++I) { + if ((*I)->isGLValue()) { + if ((*I)->getType().isConstQualified()) + classify((*I), Ignore); + } else if (isPointerToConst((*I)->getType())) { + const Expr *Ex = stripCasts(DC->getParentASTContext(), *I); + const UnaryOperator *UO = dyn_cast<UnaryOperator>(Ex); + if (UO && UO->getOpcode() == UO_AddrOf) + Ex = UO->getSubExpr(); + classify(Ex, Ignore); + } + } } void ClassifyRefs::VisitCastExpr(CastExpr *CE) { @@ -804,7 +837,7 @@ struct PruneBlocksHandler : public UninitVariablesHandler { : hadUse(numBlocks, false), hadAnyUse(false), currentBlock(0) {} - virtual ~PruneBlocksHandler() {} + ~PruneBlocksHandler() override {} /// Records if a CFGBlock had a potential use of an uninitialized variable. llvm::BitVector hadUse; |