aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Analysis
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
commit13cc256e404620c1de0cbcc4e43ce1e2dbbc4898 (patch)
tree2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /lib/Analysis
parent657bc3d9848e3be92029b2416031340988cd0111 (diff)
downloadsrc-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.tar.gz
src-13cc256e404620c1de0cbcc4e43ce1e2dbbc4898.zip
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):vendor/clang/clang-release_32-r168974
Notes
Notes: svn path=/vendor/clang/dist/; revision=243791 svn path=/vendor/clang/clang-release_32-r168974/; revision=243792; tag=vendor/clang/clang-release_32-r168974
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp41
-rw-r--r--lib/Analysis/BodyFarm.cpp374
-rw-r--r--lib/Analysis/BodyFarm.h43
-rw-r--r--lib/Analysis/CFG.cpp83
-rw-r--r--lib/Analysis/CMakeLists.txt4
-rw-r--r--lib/Analysis/FormatString.cpp57
-rw-r--r--lib/Analysis/ObjCNoReturn.cpp67
-rw-r--r--lib/Analysis/PrintfFormatString.cpp43
-rw-r--r--lib/Analysis/ReachableCode.cpp4
-rw-r--r--lib/Analysis/ScanfFormatString.cpp36
-rw-r--r--lib/Analysis/ThreadSafety.cpp340
-rw-r--r--lib/Analysis/UninitializedValues.cpp64
12 files changed, 979 insertions, 177 deletions
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 7de7f395e8a7..e7df0a813b37 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -29,13 +29,15 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
+#include "BodyFarm.h"
+
using namespace clang;
typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap;
AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d,
- const CFG::BuildOptions &buildOptions)
+ const Decl *d,
+ const CFG::BuildOptions &buildOptions)
: Manager(Mgr),
D(d),
cfgBuildOptions(buildOptions),
@@ -49,7 +51,7 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
}
AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d)
+ const Decl *d)
: Manager(Mgr),
D(d),
forcedBlkExprs(0),
@@ -62,11 +64,16 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
}
AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
- bool addImplicitDtors,
- bool addInitializers) {
+ bool addImplicitDtors,
+ bool addInitializers,
+ bool addTemporaryDtors,
+ bool synthesizeBodies)
+ : SynthesizeBodies(synthesizeBodies)
+{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
+ cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
}
void AnalysisDeclContextManager::clear() {
@@ -75,9 +82,18 @@ void AnalysisDeclContextManager::clear() {
Contexts.clear();
}
+static BodyFarm &getBodyFarm(ASTContext &C) {
+ static BodyFarm *BF = new BodyFarm(C);
+ return *BF;
+}
+
Stmt *AnalysisDeclContext::getBody() const {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->getBody();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ Stmt *Body = FD->getBody();
+ if (!Body && Manager && Manager->synthesizeBodies())
+ return getBodyFarm(getASTContext()).getBody(FD);
+ return Body;
+ }
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getBody();
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
@@ -201,6 +217,13 @@ PseudoConstantAnalysis *AnalysisDeclContext::getPseudoConstantAnalysis() {
}
AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl
+ // that has the body.
+ FD->hasBody(FD);
+ D = FD;
+ }
+
AnalysisDeclContext *&AC = Contexts[D];
if (!AC)
AC = new AnalysisDeclContext(this, D, cfgBuildOptions);
@@ -332,6 +355,10 @@ const StackFrameContext *LocationContext::getCurrentStackFrame() const {
return NULL;
}
+bool LocationContext::inTopFrame() const {
+ return getCurrentStackFrame()->inTopFrame();
+}
+
bool LocationContext::isParentOf(const LocationContext *LC) const {
do {
const LocationContext *Parent = LC->getParent();
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
new file mode 100644
index 000000000000..794ff9cc2bb1
--- /dev/null
+++ b/lib/Analysis/BodyFarm.cpp
@@ -0,0 +1,374 @@
+//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// BodyFarm is a factory for creating faux implementations for functions/methods
+// for analysis purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringSwitch.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprObjC.h"
+#include "BodyFarm.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Helper creation functions for constructing faux ASTs.
+//===----------------------------------------------------------------------===//
+
+static bool isDispatchBlock(QualType Ty) {
+ // Is it a block pointer?
+ const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
+ if (!BPT)
+ return false;
+
+ // Check if the block pointer type takes no arguments and
+ // returns void.
+ const FunctionProtoType *FT =
+ BPT->getPointeeType()->getAs<FunctionProtoType>();
+ if (!FT || !FT->getResultType()->isVoidType() ||
+ FT->getNumArgs() != 0)
+ return false;
+
+ return true;
+}
+
+namespace {
+class ASTMaker {
+public:
+ ASTMaker(ASTContext &C) : C(C) {}
+
+ /// Create a new BinaryOperator representing a simple assignment.
+ BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
+
+ /// Create a new BinaryOperator representing a comparison.
+ BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
+ BinaryOperator::Opcode Op);
+
+ /// Create a new compound stmt using the provided statements.
+ CompoundStmt *makeCompound(ArrayRef<Stmt*>);
+
+ /// Create a new DeclRefExpr for the referenced variable.
+ DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
+
+ /// Create a new UnaryOperator representing a dereference.
+ UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
+
+ /// Create an implicit cast for an integer conversion.
+ Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
+
+ /// Create an implicit cast to a builtin boolean type.
+ ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
+
+ // Create an implicit cast for lvalue-to-rvaluate conversions.
+ ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
+
+ /// Create an Objective-C bool literal.
+ ObjCBoolLiteralExpr *makeObjCBool(bool Val);
+
+ /// Create a Return statement.
+ ReturnStmt *makeReturn(const Expr *RetVal);
+
+private:
+ ASTContext &C;
+};
+}
+
+BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
+ QualType Ty) {
+ return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
+ BO_Assign, Ty, VK_RValue,
+ OK_Ordinary, SourceLocation(), false);
+}
+
+BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
+ BinaryOperator::Opcode Op) {
+ assert(BinaryOperator::isLogicalOp(Op) ||
+ BinaryOperator::isComparisonOp(Op));
+ return new (C) BinaryOperator(const_cast<Expr*>(LHS),
+ const_cast<Expr*>(RHS),
+ Op,
+ C.getLogicalOperationType(),
+ VK_RValue,
+ OK_Ordinary, SourceLocation(), false);
+}
+
+CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
+ return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()),
+ Stmts.size(),
+ SourceLocation(), SourceLocation());
+}
+
+DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
+ DeclRefExpr *DR =
+ DeclRefExpr::Create(/* Ctx = */ C,
+ /* QualifierLoc = */ NestedNameSpecifierLoc(),
+ /* TemplateKWLoc = */ SourceLocation(),
+ /* D = */ const_cast<VarDecl*>(D),
+ /* isEnclosingLocal = */ false,
+ /* NameLoc = */ SourceLocation(),
+ /* T = */ D->getType(),
+ /* VK = */ VK_LValue);
+ return DR;
+}
+
+UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
+ return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
+ VK_LValue, OK_Ordinary, SourceLocation());
+}
+
+ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
+ return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
+ if (Arg->getType() == Ty)
+ return const_cast<Expr*>(Arg);
+
+ return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
+ return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
+ const_cast<Expr*>(Arg), 0, VK_RValue);
+}
+
+ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
+ QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
+ return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
+}
+
+ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
+ return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0);
+}
+
+//===----------------------------------------------------------------------===//
+// Creation functions for faux ASTs.
+//===----------------------------------------------------------------------===//
+
+typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
+
+/// Create a fake body for dispatch_once.
+static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
+ // Check if we have at least two parameters.
+ if (D->param_size() != 2)
+ return 0;
+
+ // Check if the first parameter is a pointer to integer type.
+ const ParmVarDecl *Predicate = D->getParamDecl(0);
+ QualType PredicateQPtrTy = Predicate->getType();
+ const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
+ if (!PredicatePtrTy)
+ return 0;
+ QualType PredicateTy = PredicatePtrTy->getPointeeType();
+ if (!PredicateTy->isIntegerType())
+ return 0;
+
+ // Check if the second parameter is the proper block type.
+ const ParmVarDecl *Block = D->getParamDecl(1);
+ QualType Ty = Block->getType();
+ if (!isDispatchBlock(Ty))
+ return 0;
+
+ // Everything checks out. Create a fakse body that checks the predicate,
+ // sets it, and calls the block. Basically, an AST dump of:
+ //
+ // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
+ // if (!*predicate) {
+ // *predicate = 1;
+ // block();
+ // }
+ // }
+
+ ASTMaker M(C);
+
+ // (1) Create the call.
+ DeclRefExpr *DR = M.makeDeclRefExpr(Block);
+ ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
+ CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+ VK_RValue, SourceLocation());
+
+ // (2) Create the assignment to the predicate.
+ IntegerLiteral *IL =
+ IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
+ C.IntTy, SourceLocation());
+ BinaryOperator *B =
+ M.makeAssignment(
+ M.makeDereference(
+ M.makeLvalueToRvalue(
+ M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
+ PredicateTy),
+ M.makeIntegralCast(IL, PredicateTy),
+ PredicateTy);
+
+ // (3) Create the compound statement.
+ Stmt *Stmts[2];
+ Stmts[0] = B;
+ Stmts[1] = CE;
+ CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+
+ // (4) Create the 'if' condition.
+ ImplicitCastExpr *LValToRval =
+ M.makeLvalueToRvalue(
+ M.makeDereference(
+ M.makeLvalueToRvalue(
+ M.makeDeclRefExpr(Predicate),
+ PredicateQPtrTy),
+ PredicateTy),
+ PredicateTy);
+
+ UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
+ VK_RValue, OK_Ordinary,
+ SourceLocation());
+
+ // (5) Create the 'if' statement.
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
+ return If;
+}
+
+/// Create a fake body for dispatch_sync.
+static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
+ // Check if we have at least two parameters.
+ if (D->param_size() != 2)
+ return 0;
+
+ // Check if the second parameter is a block.
+ const ParmVarDecl *PV = D->getParamDecl(1);
+ QualType Ty = PV->getType();
+ if (!isDispatchBlock(Ty))
+ return 0;
+
+ // Everything checks out. Create a fake body that just calls the block.
+ // This is basically just an AST dump of:
+ //
+ // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
+ // block();
+ // }
+ //
+ ASTMaker M(C);
+ DeclRefExpr *DR = M.makeDeclRefExpr(PV);
+ ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
+ CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
+ VK_RValue, SourceLocation());
+ return CE;
+}
+
+static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
+{
+ // There are exactly 3 arguments.
+ if (D->param_size() != 3)
+ return 0;
+
+ // Body for:
+ // if (oldValue == *theValue) {
+ // *theValue = newValue;
+ // return YES;
+ // }
+ // else return NO;
+
+ QualType ResultTy = D->getResultType();
+ bool isBoolean = ResultTy->isBooleanType();
+ if (!isBoolean && !ResultTy->isIntegralType(C))
+ return 0;
+
+ const ParmVarDecl *OldValue = D->getParamDecl(0);
+ QualType OldValueTy = OldValue->getType();
+
+ const ParmVarDecl *NewValue = D->getParamDecl(1);
+ QualType NewValueTy = NewValue->getType();
+
+ assert(OldValueTy == NewValueTy);
+
+ const ParmVarDecl *TheValue = D->getParamDecl(2);
+ QualType TheValueTy = TheValue->getType();
+ const PointerType *PT = TheValueTy->getAs<PointerType>();
+ if (!PT)
+ return 0;
+ QualType PointeeTy = PT->getPointeeType();
+
+ ASTMaker M(C);
+ // Construct the comparison.
+ Expr *Comparison =
+ M.makeComparison(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
+ M.makeLvalueToRvalue(
+ M.makeDereference(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+ PointeeTy),
+ PointeeTy),
+ BO_EQ);
+
+ // Construct the body of the IfStmt.
+ Stmt *Stmts[2];
+ Stmts[0] =
+ M.makeAssignment(
+ M.makeDereference(
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
+ PointeeTy),
+ M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
+ NewValueTy);
+
+ Expr *BoolVal = M.makeObjCBool(true);
+ Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
+ : M.makeIntegralCast(BoolVal, ResultTy);
+ Stmts[1] = M.makeReturn(RetVal);
+ CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
+
+ // Construct the else clause.
+ BoolVal = M.makeObjCBool(false);
+ RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
+ : M.makeIntegralCast(BoolVal, ResultTy);
+ Stmt *Else = M.makeReturn(RetVal);
+
+ /// Construct the If.
+ Stmt *If =
+ new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body,
+ SourceLocation(), Else);
+
+ return If;
+}
+
+Stmt *BodyFarm::getBody(const FunctionDecl *D) {
+ D = D->getCanonicalDecl();
+
+ llvm::Optional<Stmt *> &Val = Bodies[D];
+ if (Val.hasValue())
+ return Val.getValue();
+
+ Val = 0;
+
+ if (D->getIdentifier() == 0)
+ return 0;
+
+ StringRef Name = D->getName();
+ if (Name.empty())
+ return 0;
+
+ FunctionFarmer FF;
+
+ if (Name.startswith("OSAtomicCompareAndSwap") ||
+ Name.startswith("objc_atomicCompareAndSwap")) {
+ FF = create_OSAtomicCompareAndSwap;
+ }
+ else {
+ FF = llvm::StringSwitch<FunctionFarmer>(Name)
+ .Case("dispatch_sync", create_dispatch_sync)
+ .Case("dispatch_once", create_dispatch_once)
+ .Default(NULL);
+ }
+
+ if (FF) { Val = FF(C, D); }
+ return Val.getValue();
+}
+
diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h
new file mode 100644
index 000000000000..d503cc1bcd07
--- /dev/null
+++ b/lib/Analysis/BodyFarm.h
@@ -0,0 +1,43 @@
+//== BodyFarm.h - Factory for conjuring up fake bodies -------------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// BodyFarm is a factory for creating faux implementations for functions/methods
+// for analysis purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H
+#define LLVM_CLANG_ANALYSIS_BODYFARM_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class FunctionDecl;
+class Stmt;
+
+class BodyFarm {
+public:
+ BodyFarm(ASTContext &C) : C(C) {}
+
+ /// Factory method for creating bodies for ordinary functions.
+ Stmt *getBody(const FunctionDecl *D);
+
+private:
+ typedef llvm::DenseMap<const Decl *, llvm::Optional<Stmt *> > BodyMap;
+
+ ASTContext &C;
+ BodyMap Bodies;
+};
+}
+
+#endif
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 05c53850f568..315e54380b2f 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -467,6 +467,30 @@ private:
CachedBoolEvals[S] = Result; // update or insert
return Result;
}
+ else {
+ switch (Bop->getOpcode()) {
+ default: break;
+ // For 'x & 0' and 'x * 0', we can determine that
+ // the value is always false.
+ case BO_Mul:
+ case BO_And: {
+ // If either operand is zero, we know the value
+ // must be false.
+ llvm::APSInt IntVal;
+ if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) {
+ if (IntVal.getBoolValue() == false) {
+ return TryResult(false);
+ }
+ }
+ if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) {
+ if (IntVal.getBoolValue() == false) {
+ return TryResult(false);
+ }
+ }
+ }
+ break;
+ }
+ }
}
return evaluateAsBooleanConditionNoCache(S);
@@ -682,7 +706,7 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
IsReference = FD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
- if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+ if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
IsReference);
@@ -1022,6 +1046,14 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::ExprWithCleanupsClass:
return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc);
+ case Stmt::CXXDefaultArgExprClass:
+ // FIXME: The expression inside a CXXDefaultArgExpr is owned by the
+ // called function's declaration, not by the caller. If we simply add
+ // this expression to the CFG, we could end up with the same Expr
+ // appearing multiple times.
+ // PR13385 / <rdar://problem/12156507>
+ return VisitStmt(S, asc);
+
case Stmt::CXXBindTemporaryExprClass:
return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
@@ -1585,7 +1617,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
IsReference = VD->getType()->isReferenceType();
HasTemporaries = isa<ExprWithCleanups>(Init);
- if (BuildOpts.AddImplicitDtors && HasTemporaries) {
+ if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
// Generate destructors for temporaries in initialization expression.
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
IsReference);
@@ -1616,8 +1648,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// If the type of VD is a VLA, then we must process its size expressions.
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- Block = addStmt(VA->getSizeExpr());
+ VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) {
+ if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
+ LastBlock = newBlock;
+ }
// Remove variable from local scope.
if (ScopePos && VD == *ScopePos)
@@ -1735,7 +1769,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// Add the condition as the last statement in the new block. This may create
// new blocks as the condition may contain control-flow. Any newly created
// blocks will be pointed to be "Block".
- Block = addStmt(I->getCond());
+ CFGBlock *LastBlock = addStmt(I->getCond());
// Finally, if the IfStmt contains a condition variable, add both the IfStmt
// and the condition variable initialization to the CFG.
@@ -1743,11 +1777,11 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
appendStmt(Block, I->getConditionVariableDeclStmt());
- addStmt(Init);
+ LastBlock = addStmt(Init);
}
}
- return Block;
+ return LastBlock;
}
@@ -2254,7 +2288,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
}
// The default case when not handling logical operators.
- EntryConditionBlock = ExitConditionBlock = createBlock(false);
+ ExitConditionBlock = createBlock(false);
ExitConditionBlock->setTerminator(W);
// Now add the actual condition to the condition block.
@@ -2579,7 +2613,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
Block = SwitchTerminatedBlock;
- Block = addStmt(Terminator->getCond());
+ CFGBlock *LastBlock = addStmt(Terminator->getCond());
// Finally, if the SwitchStmt contains a condition variable, add both the
// SwitchStmt and the condition variable initialization to the CFG.
@@ -2587,11 +2621,11 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
if (Expr *Init = VD->getInit()) {
autoCreateBlock();
appendStmt(Block, Terminator->getConditionVariableDeclStmt());
- addStmt(Init);
+ LastBlock = addStmt(Init);
}
}
- return Block;
+ return LastBlock;
}
static bool shouldAddCase(bool &switchExclusivelyCovered,
@@ -2775,8 +2809,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
Block = NULL;
- Block = addStmt(Terminator->getTryBlock());
- return Block;
+ return addStmt(Terminator->getTryBlock());
}
CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
@@ -2917,15 +2950,15 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
addLocalScopeAndDtors(S->getLoopVarStmt());
// Populate a new block to contain the loop body and loop variable.
- Block = addStmt(S->getBody());
+ addStmt(S->getBody());
if (badCFG)
return 0;
- Block = addStmt(S->getLoopVarStmt());
+ CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
if (badCFG)
return 0;
// This new body block is a successor to our condition block.
- addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block);
+ addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : LoopVarStmtBlock);
}
// Link up the condition block with the code that follows the loop (the
@@ -2940,7 +2973,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
AddStmtChoice asc) {
- if (BuildOpts.AddImplicitDtors) {
+ if (BuildOpts.AddTemporaryDtors) {
// If adding implicit destructors visit the full expression for adding
// destructors of temporaries.
VisitForTemporaryDtors(E->getSubExpr());
@@ -3020,6 +3053,8 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
}
CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) {
+ assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors);
+
tryAgain:
if (!E) {
badCFG = true;
@@ -3449,12 +3484,12 @@ class StmtPrinterHelper : public PrinterHelper {
StmtMapTy StmtMap;
DeclMapTy DeclMap;
signed currentBlock;
- unsigned currentStmt;
+ unsigned currStmt;
const LangOptions &LangOpts;
public:
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
- : currentBlock(0), currentStmt(0), LangOpts(LO)
+ : currentBlock(0), currStmt(0), LangOpts(LO)
{
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
unsigned j = 1;
@@ -3515,7 +3550,7 @@ public:
const LangOptions &getLangOpts() const { return LangOpts; }
void setBlockID(signed i) { currentBlock = i; }
- void setStmtID(unsigned i) { currentStmt = i; }
+ void setStmtID(unsigned i) { currStmt = i; }
virtual bool handledStmt(Stmt *S, raw_ostream &OS) {
StmtMapTy::iterator I = StmtMap.find(S);
@@ -3524,7 +3559,7 @@ public:
return false;
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
- && I->second.second == currentStmt) {
+ && I->second.second == currStmt) {
return false;
}
@@ -3539,7 +3574,7 @@ public:
return false;
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
- && I->second.second == currentStmt) {
+ && I->second.second == currStmt) {
return false;
}
@@ -3831,8 +3866,8 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
if (Helper) Helper->setBlockID(-1);
- CFGBlockTerminatorPrint TPrinter(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
+ PrintingPolicy PP(Helper ? Helper->getLangOpts() : LangOptions());
+ CFGBlockTerminatorPrint TPrinter(OS, Helper, PP);
TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt()));
OS << '\n';
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index d57e4813ca02..ca166669fc89 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -1,13 +1,15 @@
add_clang_library(clangAnalysis
AnalysisDeclContext.cpp
- CallGraph.cpp
+ BodyFarm.cpp
CFG.cpp
CFGReachabilityAnalysis.cpp
CFGStmtMap.cpp
+ CallGraph.cpp
CocoaConventions.cpp
Dominators.cpp
FormatString.cpp
LiveVariables.cpp
+ ObjCNoReturn.cpp
PostOrderCFGView.cpp
PrintfFormatString.cpp
ProgramPoint.cpp
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index e7ea48688dae..73063b5132c8 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -14,6 +14,7 @@
#include "FormatStringParsing.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -489,9 +490,12 @@ analyze_format_string::LengthModifier::toString() const {
const char *ConversionSpecifier::toString() const {
switch (kind) {
case dArg: return "d";
+ case DArg: return "D";
case iArg: return "i";
case oArg: return "o";
+ case OArg: return "O";
case uArg: return "u";
+ case UArg: return "U";
case xArg: return "x";
case XArg: return "X";
case fArg: return "f";
@@ -523,6 +527,29 @@ const char *ConversionSpecifier::toString() const {
return NULL;
}
+llvm::Optional<ConversionSpecifier>
+ConversionSpecifier::getStandardSpecifier() const {
+ ConversionSpecifier::Kind NewKind;
+
+ switch (getKind()) {
+ default:
+ return llvm::Optional<ConversionSpecifier>();
+ case DArg:
+ NewKind = dArg;
+ break;
+ case UArg:
+ NewKind = uArg;
+ break;
+ case OArg:
+ NewKind = oArg;
+ break;
+ }
+
+ ConversionSpecifier FixedCS(*this);
+ FixedCS.setKind(NewKind);
+ return FixedCS;
+}
+
//===----------------------------------------------------------------------===//
// Methods on OptionalAmount.
//===----------------------------------------------------------------------===//
@@ -548,7 +575,7 @@ void OptionalAmount::toString(raw_ostream &os) const {
}
}
-bool FormatSpecifier::hasValidLengthModifier() const {
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
switch (LM.getKind()) {
case LengthModifier::None:
return true;
@@ -563,9 +590,12 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case LengthModifier::AsPtrDiff:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::nArg:
@@ -578,9 +608,12 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case LengthModifier::AsLong:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -611,14 +644,15 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case ConversionSpecifier::gArg:
case ConversionSpecifier::GArg:
return true;
- // GNU extension.
+ // GNU libc extension.
case ConversionSpecifier::dArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
case ConversionSpecifier::uArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
- return true;
+ return !Target.getTriple().isOSDarwin() &&
+ !Target.getTriple().isOSWindows();
default:
return false;
}
@@ -697,6 +731,9 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt)
return LangOpt.ObjC1 || LangOpt.ObjC2;
case ConversionSpecifier::InvalidSpecifier:
case ConversionSpecifier::PrintErrno:
+ case ConversionSpecifier::DArg:
+ case ConversionSpecifier::OArg:
+ case ConversionSpecifier::UArg:
return false;
}
llvm_unreachable("Invalid ConversionSpecifier Kind!");
@@ -719,6 +756,20 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
return true;
}
+llvm::Optional<LengthModifier>
+FormatSpecifier::getCorrectedLengthModifier() const {
+ if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
+ if (LM.getKind() == LengthModifier::AsLongDouble ||
+ LM.getKind() == LengthModifier::AsQuad) {
+ LengthModifier FixedLM(LM);
+ FixedLM.setKind(LengthModifier::AsLongLong);
+ return FixedLM;
+ }
+ }
+
+ return llvm::Optional<LengthModifier>();
+}
+
bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LengthModifier &LM) {
assert(isa<TypedefType>(QT) && "Expected a TypedefType");
diff --git a/lib/Analysis/ObjCNoReturn.cpp b/lib/Analysis/ObjCNoReturn.cpp
new file mode 100644
index 000000000000..52d844bf9dd8
--- /dev/null
+++ b/lib/Analysis/ObjCNoReturn.cpp
@@ -0,0 +1,67 @@
+//= ObjCNoReturn.cpp - Handling of Cocoa APIs known not to return --*- C++ -*---
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements special handling of recognizing ObjC API hooks that
+// do not return but aren't marked as such in API headers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+
+using namespace clang;
+
+static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
+ if (!Class)
+ return false;
+ if (Class->getIdentifier() == II)
+ return true;
+ return isSubclass(Class->getSuperClass(), II);
+}
+
+ObjCNoReturn::ObjCNoReturn(ASTContext &C)
+ : RaiseSel(GetNullarySelector("raise", C)),
+ NSExceptionII(&C.Idents.get("NSException"))
+{
+ // Generate selectors.
+ SmallVector<IdentifierInfo*, 3> II;
+
+ // raise:format:
+ II.push_back(&C.Idents.get("raise"));
+ II.push_back(&C.Idents.get("format"));
+ NSExceptionInstanceRaiseSelectors[0] =
+ C.Selectors.getSelector(II.size(), &II[0]);
+
+ // raise:format:arguments:
+ II.push_back(&C.Idents.get("arguments"));
+ NSExceptionInstanceRaiseSelectors[1] =
+ C.Selectors.getSelector(II.size(), &II[0]);
+}
+
+
+bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) {
+ Selector S = ME->getSelector();
+
+ if (ME->isInstanceMessage()) {
+ // Check for the "raise" message.
+ return S == RaiseSel;
+ }
+
+ if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) {
+ if (isSubclass(ID, NSExceptionII)) {
+ for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
+ if (S == NSExceptionInstanceRaiseSelectors[i])
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 9e4c0fec4c04..2fa5a88f2c71 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
using clang::analyze_format_string::ArgType;
@@ -52,7 +53,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
unsigned &argIndex,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
@@ -196,6 +198,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
+ // Apple-specific
+ case 'D':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::DArg;
+ break;
+ case 'O':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::OArg;
+ break;
+ case 'U':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::UArg;
+ break;
}
PrintfConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
@@ -212,18 +227,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
const char *I,
const char *E,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
- LO);
+ LO, Target);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
- return true;;
+ return true;
// Did we exhaust the string or encounter an error that
// we can recover from?
if (!FSR.hasValue())
@@ -482,9 +498,11 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we are done.
- const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
- if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT))
- return true;
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
+ if (ATR.isValid() && ATR.matchesType(Ctx, QT))
+ return true;
+ }
// Set conversion specifier and disable any flags which do not apply to it.
// Let typedefs to char fall through to int, as %c is silly for uint8_t.
@@ -549,6 +567,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const {
// The plus prefix only makes sense for signed conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
@@ -572,6 +591,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() const {
// Alternate form flag only valid with the oxXaAeEfFgG conversions
switch (CS.getKind()) {
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -596,9 +616,12 @@ bool PrintfSpecifier::hasValidLeadingZeros() const {
// Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
@@ -623,6 +646,7 @@ bool PrintfSpecifier::hasValidSpacePrefix() const {
// The space prefix only makes sense for signed conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
@@ -659,8 +683,10 @@ bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::fArg:
case ConversionSpecifier::FArg:
case ConversionSpecifier::gArg:
@@ -678,9 +704,12 @@ bool PrintfSpecifier::hasValidPrecision() const {
// Precision is only valid with the diouxXaAeEfFgGs conversions
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::aArg:
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index bb63e2c18490..11f2ebe9ad2d 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -112,8 +112,8 @@ const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
static int SrcCmp(const void *p1, const void *p2) {
return
- ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
- ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
+ ((const std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() <
+ ((const std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart();
}
unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 2942400621d1..574e56a5e068 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
using clang::analyze_format_string::ArgType;
@@ -67,7 +68,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
unsigned &argIndex,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
using namespace clang::analyze_scanf;
const char *I = Beg;
@@ -172,6 +174,20 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
case 'o': k = ConversionSpecifier::oArg; break;
case 's': k = ConversionSpecifier::sArg; break;
case 'p': k = ConversionSpecifier::pArg; break;
+ // Apple extensions
+ // Apple-specific
+ case 'D':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::DArg;
+ break;
+ case 'O':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::OArg;
+ break;
+ case 'U':
+ if (Target.getTriple().isOSDarwin())
+ k = ConversionSpecifier::UArg;
+ break;
}
ScanfConversionSpecifier CS(conversionPosition, k);
if (k == ScanfConversionSpecifier::ScanListArg) {
@@ -202,6 +218,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
switch(CS.getKind()) {
// Signed int.
case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
switch (LM.getKind()) {
case LengthModifier::None:
@@ -233,7 +250,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
// Unsigned int.
case ConversionSpecifier::oArg:
+ case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
switch (LM.getKind()) {
@@ -430,9 +449,11 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
- const analyze_scanf::ArgType &AT = getArgType(Ctx);
- if (hasValidLengthModifier() && AT.isValid() && AT.matchesType(Ctx, QT))
- return true;
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ const analyze_scanf::ArgType &AT = getArgType(Ctx);
+ if (AT.isValid() && AT.matchesType(Ctx, QT))
+ return true;
+ }
// Figure out the conversion specifier.
if (PT->isRealFloatingType())
@@ -463,18 +484,19 @@ void ScanfSpecifier::toString(raw_ostream &os) const {
bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
const char *I,
const char *E,
- const LangOptions &LO) {
+ const LangOptions &LO,
+ const TargetInfo &Target) {
unsigned argIndex = 0;
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
- LO);
+ LO, Target);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
- return true;;
+ return true;
// Did we exhaust the string or encounter an error that
// we can recover from?
if (!FSR.hasValue())
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 5954682579d8..c7f1f62cb57d 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -70,27 +70,28 @@ namespace {
class SExpr {
private:
enum ExprOp {
- EOP_Nop, //< No-op
- EOP_Wildcard, //< Matches anything.
- EOP_This, //< This keyword.
- EOP_NVar, //< Named variable.
- EOP_LVar, //< Local variable.
- EOP_Dot, //< Field access
- EOP_Call, //< Function call
- EOP_MCall, //< Method call
- EOP_Index, //< Array index
- EOP_Unary, //< Unary operation
- EOP_Binary, //< Binary operation
- EOP_Unknown //< Catchall for everything else
+ EOP_Nop, ///< No-op
+ EOP_Wildcard, ///< Matches anything.
+ EOP_Universal, ///< Universal lock.
+ EOP_This, ///< This keyword.
+ EOP_NVar, ///< Named variable.
+ EOP_LVar, ///< Local variable.
+ EOP_Dot, ///< Field access
+ EOP_Call, ///< Function call
+ EOP_MCall, ///< Method call
+ EOP_Index, ///< Array index
+ EOP_Unary, ///< Unary operation
+ EOP_Binary, ///< Binary operation
+ EOP_Unknown ///< Catchall for everything else
};
class SExprNode {
private:
- unsigned char Op; //< Opcode of the root node
- unsigned char Flags; //< Additional opcode-specific data
- unsigned short Sz; //< Number of child nodes
- const void* Data; //< Additional opcode-specific data
+ unsigned char Op; ///< Opcode of the root node
+ unsigned char Flags; ///< Additional opcode-specific data
+ unsigned short Sz; ///< Number of child nodes
+ const void* Data; ///< Additional opcode-specific data
public:
SExprNode(ExprOp O, unsigned F, const void* D)
@@ -118,18 +119,19 @@ private:
unsigned arity() const {
switch (Op) {
- case EOP_Nop: return 0;
- case EOP_Wildcard: return 0;
- case EOP_NVar: return 0;
- case EOP_LVar: return 0;
- case EOP_This: return 0;
- case EOP_Dot: return 1;
- case EOP_Call: return Flags+1; // First arg is function.
- case EOP_MCall: return Flags+1; // First arg is implicit obj.
- case EOP_Index: return 2;
- case EOP_Unary: return 1;
- case EOP_Binary: return 2;
- case EOP_Unknown: return Flags;
+ case EOP_Nop: return 0;
+ case EOP_Wildcard: return 0;
+ case EOP_Universal: return 0;
+ case EOP_NVar: return 0;
+ case EOP_LVar: return 0;
+ case EOP_This: return 0;
+ case EOP_Dot: return 1;
+ case EOP_Call: return Flags+1; // First arg is function.
+ case EOP_MCall: return Flags+1; // First arg is implicit obj.
+ case EOP_Index: return 2;
+ case EOP_Unary: return 1;
+ case EOP_Binary: return 2;
+ case EOP_Unknown: return Flags;
}
return 0;
}
@@ -194,6 +196,11 @@ private:
return NodeVec.size()-1;
}
+ unsigned makeUniversal() {
+ NodeVec.push_back(SExprNode(EOP_Universal, 0, 0));
+ return NodeVec.size()-1;
+ }
+
unsigned makeNamedVar(const NamedDecl *D) {
NodeVec.push_back(SExprNode(EOP_NVar, 0, D));
return NodeVec.size()-1;
@@ -219,8 +226,21 @@ private:
return NodeVec.size()-1;
}
- unsigned makeMCall(unsigned NumArgs, const NamedDecl *D) {
- NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, D));
+ // Grab the very first declaration of virtual method D
+ const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) {
+ while (true) {
+ D = D->getCanonicalDecl();
+ CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
+ E = D->end_overridden_methods();
+ if (I == E)
+ return D; // Method does not override anything
+ D = *I; // FIXME: this does not work with multiple inheritance.
+ }
+ return 0;
+ }
+
+ unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) {
+ NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, getFirstVirtualDecl(D)));
return NodeVec.size()-1;
}
@@ -300,8 +320,9 @@ private:
} else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
// When calling a function with a lock_returned attribute, replace
// the function call with the expression in lock_returned.
- if (LockReturnedAttr* At =
- CMCE->getMethodDecl()->getAttr<LockReturnedAttr>()) {
+ CXXMethodDecl* MD =
+ cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl());
+ if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CMCE->getMethodDecl());
LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument();
LRCallCtx.SelfArrow =
@@ -320,8 +341,7 @@ private:
return buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx, NDeref);
}
unsigned NumCallArgs = CMCE->getNumArgs();
- unsigned Root =
- makeMCall(NumCallArgs, CMCE->getMethodDecl()->getCanonicalDecl());
+ unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl());
unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx);
Expr** CallArgs = CMCE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
@@ -330,8 +350,9 @@ private:
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
} else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- if (LockReturnedAttr* At =
- CE->getDirectCallee()->getAttr<LockReturnedAttr>()) {
+ FunctionDecl* FD =
+ cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl());
+ if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CE->getDirectCallee());
LRCallCtx.NumArgs = CE->getNumArgs();
LRCallCtx.FunArgs = CE->getArgs();
@@ -442,9 +463,23 @@ private:
/// \param DeclExp An expression involving the Decl on which the attribute
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
- void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
+ void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D,
+ VarDecl *SelfDecl = 0) {
CallingContext CallCtx(D);
+ if (MutexExp) {
+ if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
+ if (SLit->getString() == StringRef("*"))
+ // The "*" expr is a universal lock, which essentially turns off
+ // checks until it is removed from the lockset.
+ makeUniversal();
+ else
+ // Ignore other string literals for now.
+ makeNop();
+ return;
+ }
+ }
+
// If we are processing a raw attribute expression, with no substitutions.
if (DeclExp == 0) {
buildSExpr(MutexExp, 0);
@@ -465,7 +500,7 @@ private:
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
- CallCtx.SelfArg = 0; // FIXME -- get the parent from DeclStmt
+ CallCtx.SelfArg = 0; // Will be set below
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (D && isa<CXXDestructorDecl>(D)) {
@@ -473,14 +508,26 @@ private:
CallCtx.SelfArg = DeclExp;
}
- // If the attribute has no arguments, then assume the argument is "this".
- if (MutexExp == 0) {
- buildSExpr(CallCtx.SelfArg, 0);
+ // Hack to handle constructors, where self cannot be recovered from
+ // the expression.
+ if (SelfDecl && !CallCtx.SelfArg) {
+ DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue,
+ SelfDecl->getLocation());
+ CallCtx.SelfArg = &SelfDRE;
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (MutexExp == 0)
+ buildSExpr(CallCtx.SelfArg, 0);
+ else // For most attributes.
+ buildSExpr(MutexExp, &CallCtx);
return;
}
- // For most attributes.
- buildSExpr(MutexExp, &CallCtx);
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (MutexExp == 0)
+ buildSExpr(CallCtx.SelfArg, 0);
+ else // For most attributes.
+ buildSExpr(MutexExp, &CallCtx);
}
/// \brief Get index of next sibling of node i.
@@ -496,8 +543,9 @@ public:
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
/// Caller must check isValid() after construction.
- SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D) {
- buildSExprFromExpr(MutexExp, DeclExp, D);
+ SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D,
+ VarDecl *SelfDecl=0) {
+ buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
}
/// Return true if this is a valid decl sequence.
@@ -506,6 +554,17 @@ public:
return !NodeVec.empty();
}
+ bool shouldIgnore() const {
+ // Nop is a mutex that we have decided to deliberately ignore.
+ assert(NodeVec.size() > 0 && "Invalid Mutex");
+ return NodeVec[0].kind() == EOP_Nop;
+ }
+
+ bool isUniversal() const {
+ assert(NodeVec.size() > 0 && "Invalid Mutex");
+ return NodeVec[0].kind() == EOP_Universal;
+ }
+
/// Issue a warning about an invalid lock expression
static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
Expr *DeclExp, const NamedDecl* D) {
@@ -528,7 +587,9 @@ public:
bool matches(const SExpr &Other, unsigned i = 0, unsigned j = 0) const {
if (NodeVec[i].matches(Other.NodeVec[j])) {
- unsigned n = NodeVec[i].arity();
+ unsigned ni = NodeVec[i].arity();
+ unsigned nj = Other.NodeVec[j].arity();
+ unsigned n = (ni < nj) ? ni : nj;
bool Result = true;
unsigned ci = i+1; // first child of i
unsigned cj = j+1; // first child of j
@@ -541,6 +602,15 @@ public:
return false;
}
+ // A partial match between a.mu and b.mu returns true a and b have the same
+ // type (and thus mu refers to the same mutex declaration), regardless of
+ // whether a and b are different objects or not.
+ bool partiallyMatches(const SExpr &Other) const {
+ if (NodeVec[0].kind() == EOP_Dot)
+ return NodeVec[0].matches(Other.NodeVec[0]);
+ return false;
+ }
+
/// \brief Pretty print a lock expression for use in error messages.
std::string toString(unsigned i = 0) const {
assert(isValid());
@@ -553,6 +623,8 @@ public:
return "_";
case EOP_Wildcard:
return "(?)";
+ case EOP_Universal:
+ return "*";
case EOP_This:
return "this";
case EOP_NVar:
@@ -695,6 +767,10 @@ struct LockData {
ID.AddInteger(AcquireLoc.getRawEncoding());
ID.AddInteger(LKind);
}
+
+ bool isAtLeast(LockKind LK) {
+ return (LK == LK_Shared) || (LKind == LK_Exclusive);
+ }
};
@@ -780,9 +856,28 @@ public:
return false;
}
- LockData* findLock(FactManager& FM, const SExpr& M) const {
+ LockData* findLock(FactManager &FM, const SExpr &M) const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ const SExpr &Exp = FM[*I].MutID;
+ if (Exp.matches(M))
+ return &FM[*I].LDat;
+ }
+ return 0;
+ }
+
+ LockData* findLockUniv(FactManager &FM, const SExpr &M) const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ const SExpr &Exp = FM[*I].MutID;
+ if (Exp.matches(M) || Exp.isUniversal())
+ return &FM[*I].LDat;
+ }
+ return 0;
+ }
+
+ FactEntry* findPartialMatch(FactManager &FM, const SExpr &M) const {
for (const_iterator I=begin(), E=end(); I != E; ++I) {
- if (FM[*I].MutID.matches(M)) return &FM[*I].LDat;
+ const SExpr& Exp = FM[*I].MutID;
+ if (Exp.partiallyMatches(M)) return &FM[*I];
}
return 0;
}
@@ -811,6 +906,7 @@ struct CFGBlockInfo {
SourceLocation EntryLoc; // Location of first statement in block
SourceLocation ExitLoc; // Location of last statement in block.
unsigned EntryIndex; // Used to replay contexts later
+ bool Reachable; // Is this block reachable?
const FactSet &getSet(CFGBlockSide Side) const {
return Side == CBS_Entry ? EntrySet : ExitSet;
@@ -821,7 +917,7 @@ struct CFGBlockInfo {
private:
CFGBlockInfo(LocalVarContext EmptyCtx)
- : EntryContext(EmptyCtx), ExitContext(EmptyCtx)
+ : EntryContext(EmptyCtx), ExitContext(EmptyCtx), Reachable(false)
{ }
public:
@@ -939,7 +1035,7 @@ public:
return;
}
Dec->printName(llvm::errs());
- llvm::errs() << "." << i << " " << ((void*) Dec);
+ llvm::errs() << "." << i << " " << ((const void*) Dec);
}
/// Dumps an ASCII representation of the variable map to llvm::errs()
@@ -1339,7 +1435,7 @@ public:
template <typename AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
- const NamedDecl *D);
+ const NamedDecl *D, VarDecl *SelfDecl=0);
template <class AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
@@ -1376,6 +1472,9 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
const LockData &LDat) {
// FIXME: deal with acquired before/after annotations.
// FIXME: Don't always warn when we have support for reentrant locks.
+ if (Mutex.shouldIgnore())
+ return;
+
if (FSet.findLock(FactMan, Mutex)) {
Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
} else {
@@ -1385,12 +1484,15 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
/// \brief Remove a lock from the lockset, warning if the lock is not there.
-/// \param LockExp The lock expression corresponding to the lock to be removed
+/// \param Mutex The lock expression corresponding to the lock to be removed
/// \param UnlockLoc The source location of the unlock (only used in error msg)
void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
const SExpr &Mutex,
SourceLocation UnlockLoc,
bool FullyRemove) {
+ if (Mutex.shouldIgnore())
+ return;
+
const LockData *LDat = FSet.findLock(FactMan, Mutex);
if (!LDat) {
Handler.handleUnmatchedUnlock(Mutex.toString(), UnlockLoc);
@@ -1423,12 +1525,13 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
/// and push them onto Mtxs, discarding any duplicates.
template <typename AttrType>
void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
- Expr *Exp, const NamedDecl *D) {
+ Expr *Exp, const NamedDecl *D,
+ VarDecl *SelfDecl) {
typedef typename AttrType::args_iterator iterator_type;
if (Attr->args_size() == 0) {
// The mutex held is the "this" object.
- SExpr Mu(0, Exp, D);
+ SExpr Mu(0, Exp, D, SelfDecl);
if (!Mu.isValid())
SExpr::warnInvalidLock(Handler, 0, Exp, D);
else
@@ -1437,7 +1540,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
}
for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
- SExpr Mu(*I, Exp, D);
+ SExpr Mu(*I, Exp, D, SelfDecl);
if (!Mu.isValid())
SExpr::warnInvalidLock(Handler, *I, Exp, D);
else
@@ -1512,6 +1615,9 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
else if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Cond)) {
return getTrylockCallExpr(CE->getSubExpr(), C, Negate);
}
+ else if (const ExprWithCleanups* EWC = dyn_cast<ExprWithCleanups>(Cond)) {
+ return getTrylockCallExpr(EWC->getSubExpr(), C, Negate);
+ }
else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) {
const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C);
return getTrylockCallExpr(E, C, Negate);
@@ -1591,7 +1697,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
case attr::SharedTrylockFunction: {
SharedTrylockFunctionAttr *A =
cast<SharedTrylockFunctionAttr>(Attr);
- getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl,
+ getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl,
PredBlock, CurrBlock, A->getSuccessValue(), Negate);
break;
}
@@ -1631,39 +1737,12 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
+ void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp);
void checkAccess(Expr *Exp, AccessKind AK);
void checkDereference(Expr *Exp, AccessKind AK);
void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
- /// \brief Returns true if the lockset contains a lock, regardless of whether
- /// the lock is held exclusively or shared.
- bool locksetContains(const SExpr &Mu) const {
- return FSet.findLock(Analyzer->FactMan, Mu);
- }
-
- /// \brief Returns true if the lockset contains a lock with the passed in
- /// locktype.
- bool locksetContains(const SExpr &Mu, LockKind KindRequested) const {
- const LockData *LockHeld = FSet.findLock(Analyzer->FactMan, Mu);
- return (LockHeld && KindRequested == LockHeld->LKind);
- }
-
- /// \brief Returns true if the lockset contains a lock with at least the
- /// passed in locktype. So for example, if we pass in LK_Shared, this function
- /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
- /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
- bool locksetContainsAtLeast(const SExpr &Lock,
- LockKind KindRequested) const {
- switch (KindRequested) {
- case LK_Shared:
- return locksetContains(Lock);
- case LK_Exclusive:
- return locksetContains(Lock, KindRequested);
- }
- llvm_unreachable("Unknown LockKind");
- }
-
public:
BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
: StmtVisitor<BuildLockset>(),
@@ -1701,13 +1780,57 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
LockKind LK = getLockKindFromAccessKind(AK);
SExpr Mutex(MutexExp, Exp, D);
- if (!Mutex.isValid())
+ if (!Mutex.isValid()) {
SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
- else if (!locksetContainsAtLeast(Mutex, LK))
+ return;
+ } else if (Mutex.shouldIgnore()) {
+ return;
+ }
+
+ LockData* LDat = FSet.findLockUniv(Analyzer->FactMan, Mutex);
+ bool NoError = true;
+ if (!LDat) {
+ // No exact match found. Look for a partial match.
+ FactEntry* FEntry = FSet.findPartialMatch(Analyzer->FactMan, Mutex);
+ if (FEntry) {
+ // Warn that there's no precise match.
+ LDat = &FEntry->LDat;
+ std::string PartMatchStr = FEntry->MutID.toString();
+ StringRef PartMatchName(PartMatchStr);
+ Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
+ Exp->getExprLoc(), &PartMatchName);
+ } else {
+ // Warn that there's no match at all.
+ Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
+ Exp->getExprLoc());
+ }
+ NoError = false;
+ }
+ // Make sure the mutex we found is the right kind.
+ if (NoError && LDat && !LDat->isAtLeast(LK))
Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
Exp->getExprLoc());
}
+/// \brief Warn if the LSet contains the given lock.
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
+ Expr *MutexExp) {
+ SExpr Mutex(MutexExp, Exp, D);
+ if (!Mutex.isValid()) {
+ SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
+ return;
+ }
+
+ LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex);
+ if (LDat) {
+ std::string DeclName = D->getNameAsString();
+ StringRef DeclNameSR (DeclName);
+ Analyzer->Handler.handleFunExcludesLock(DeclNameSR, Mutex.toString(),
+ Exp->getExprLoc());
+ }
+}
+
+
/// \brief This method identifies variable dereferences and checks pt_guarded_by
/// and pt_guarded_var annotations. Note that we only check these annotations
/// at the time a pointer is dereferenced.
@@ -1776,7 +1899,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// to our lockset with kind exclusive.
case attr::ExclusiveLockFunction: {
ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(At);
- Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D);
+ Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D, VD);
break;
}
@@ -1784,7 +1907,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// to our lockset with kind shared.
case attr::SharedLockFunction: {
SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(At);
- Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D);
+ Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D, VD);
break;
}
@@ -1792,7 +1915,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
// mutexes from the lockset, and flag a warning if they are not there.
case attr::UnlockFunction: {
UnlockFunctionAttr *A = cast<UnlockFunctionAttr>(At);
- Analyzer->getMutexIDs(LocksToRemove, A, Exp, D);
+ Analyzer->getMutexIDs(LocksToRemove, A, Exp, D, VD);
break;
}
@@ -1816,15 +1939,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
case attr::LocksExcluded: {
LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
+
for (LocksExcludedAttr::args_iterator I = A->args_begin(),
E = A->args_end(); I != E; ++I) {
- SExpr Mutex(*I, Exp, D);
- if (!Mutex.isValid())
- SExpr::warnInvalidLock(Analyzer->Handler, *I, Exp, D);
- else if (locksetContains(Mutex))
- Analyzer->Handler.handleFunExcludesLock(D->getName(),
- Mutex.toString(),
- Exp->getExprLoc());
+ warnIfMutexHeld(D, Exp, *I);
}
break;
}
@@ -1973,8 +2091,8 @@ void BuildLockset::VisitDeclStmt(DeclStmt *S) {
/// are the same. In the event of a difference, we use the intersection of these
/// two locksets at the start of D.
///
-/// \param LSet1 The first lockset.
-/// \param LSet2 The second lockset.
+/// \param FSet1 The first lockset.
+/// \param FSet2 The second lockset.
/// \param JoinLoc The location of the join point for error reporting
/// \param LEK1 The error message to report if a mutex is missing from LSet1
/// \param LEK2 The error message to report if a mutex is missing from Lset2
@@ -2012,7 +2130,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat2.Managed)
+ else if (!LDat2.Managed && !FSet2Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),
LDat2.AcquireLoc,
JoinLoc, LEK1);
@@ -2035,7 +2153,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat1.Managed)
+ else if (!LDat1.Managed && !FSet1Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),
LDat1.AcquireLoc,
JoinLoc, LEK2);
@@ -2081,6 +2199,9 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+ // Mark entry block as reachable
+ BlockInfo[CFGraph->getEntry().getBlockID()].Reachable = true;
+
// Compute SSA names for local variables
LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo);
@@ -2168,10 +2289,16 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
continue;
+ int PrevBlockID = (*PI)->getBlockID();
+ CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
// Ignore edges from blocks that can't return.
- if ((*PI)->hasNoReturnElement())
+ if ((*PI)->hasNoReturnElement() || !PrevBlockInfo->Reachable)
continue;
+ // Okay, we can reach this block from the entry.
+ CurrBlockInfo->Reachable = true;
+
// If the previous block ended in a 'continue' or 'break' statement, then
// a difference in locksets is probably due to a bug in that block, rather
// than in some other predecessor. In that case, keep the other
@@ -2183,8 +2310,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
- int PrevBlockID = (*PI)->getBlockID();
- CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
+
FactSet PrevLockset;
getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
@@ -2198,6 +2324,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
+ // Skip rest of block if it's not reachable.
+ if (!CurrBlockInfo->Reachable)
+ continue;
+
// Process continue and break blocks. Assume that the lockset for the
// resulting block is unaffected by any discrepancies in them.
for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size();
@@ -2287,6 +2417,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CFGBlockInfo *Initial = &BlockInfo[CFGraph->getEntry().getBlockID()];
CFGBlockInfo *Final = &BlockInfo[CFGraph->getExit().getBlockID()];
+ // Skip the final check if the exit block is unreachable.
+ if (!Final->Reachable)
+ return;
+
// FIXME: Should we call this function for all blocks which exit the function?
intersectAndWarn(Initial->EntrySet, Final->ExitSet,
Final->ExitLoc,
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 858be4561caf..b2e27cad1f39 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -13,6 +13,7 @@
#include <utility>
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/PackedVector.h"
#include "llvm/ADT/DenseMap.h"
@@ -22,6 +23,7 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -97,22 +99,21 @@ static bool isAlwaysUninit(const Value v) {
namespace {
-typedef llvm::PackedVector<Value, 2> ValueVector;
+typedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
class CFGBlockValues {
const CFG &cfg;
- std::vector<ValueVector*> vals;
+ SmallVector<ValueVector, 8> vals;
ValueVector scratch;
DeclToIndex declToIndex;
public:
CFGBlockValues(const CFG &cfg);
- ~CFGBlockValues();
unsigned getNumEntries() const { return declToIndex.size(); }
void computeSetOfDeclarations(const DeclContext &dc);
ValueVector &getValueVector(const CFGBlock *block) {
- return *vals[block->getBlockID()];
+ return vals[block->getBlockID()];
}
void setAllScratchValues(Value V);
@@ -138,12 +139,6 @@ public:
CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {}
-CFGBlockValues::~CFGBlockValues() {
- for (std::vector<ValueVector*>::iterator I = vals.begin(), E = vals.end();
- I != E; ++I)
- delete *I;
-}
-
void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
declToIndex.computeMap(dc);
unsigned decls = declToIndex.size();
@@ -153,7 +148,7 @@ void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
return;
vals.resize(n);
for (unsigned i = 0; i < n; ++i)
- vals[i] = new ValueVector(decls);
+ vals[i].resize(decls);
}
#if DEBUG_LOGGING
@@ -412,6 +407,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
const CFGBlock *block;
AnalysisDeclContext &ac;
const ClassifyRefs &classification;
+ ObjCNoReturn objCNoRet;
UninitVariablesHandler *handler;
public:
@@ -420,16 +416,18 @@ public:
const ClassifyRefs &classification,
UninitVariablesHandler *handler)
: vals(vals), cfg(cfg), block(block), ac(ac),
- classification(classification), handler(handler) {}
+ classification(classification), objCNoRet(ac.getASTContext()),
+ handler(handler) {}
void reportUse(const Expr *ex, const VarDecl *vd);
- void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
+ void VisitBinaryOperator(BinaryOperator *bo);
void VisitBlockExpr(BlockExpr *be);
void VisitCallExpr(CallExpr *ce);
- void VisitDeclStmt(DeclStmt *ds);
void VisitDeclRefExpr(DeclRefExpr *dr);
- void VisitBinaryOperator(BinaryOperator *bo);
+ void VisitDeclStmt(DeclStmt *ds);
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
+ void VisitObjCMessageExpr(ObjCMessageExpr *ME);
bool isTrackedVar(const VarDecl *vd) {
return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
@@ -605,14 +603,26 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
}
void TransferFunctions::VisitCallExpr(CallExpr *ce) {
- // After a call to a function like setjmp or vfork, any variable which is
- // initialized anywhere within this function may now be initialized. For now,
- // just assume such a call initializes all variables.
- // FIXME: Only mark variables as initialized if they have an initializer which
- // is reachable from here.
- Decl *Callee = ce->getCalleeDecl();
- if (Callee && Callee->hasAttr<ReturnsTwiceAttr>())
- vals.setAllScratchValues(Initialized);
+ if (Decl *Callee = ce->getCalleeDecl()) {
+ if (Callee->hasAttr<ReturnsTwiceAttr>()) {
+ // After a call to a function like setjmp or vfork, any variable which is
+ // initialized anywhere within this function may now be initialized. For
+ // now, just assume such a call initializes all variables. FIXME: Only
+ // mark variables as initialized if they have an initializer which is
+ // reachable from here.
+ vals.setAllScratchValues(Initialized);
+ }
+ else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
+ // Functions labeled like "analyzer_noreturn" are often used to denote
+ // "panic" functions that in special debug situations can still return,
+ // but for the most part should not be treated as returning. This is a
+ // useful annotation borrowed from the static analyzer that is useful for
+ // suppressing branch-specific false positives when we call one of these
+ // functions but keep pretending the path continues (when in reality the
+ // user doesn't care).
+ vals.setAllScratchValues(Unknown);
+ }
+ }
}
void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
@@ -677,6 +687,14 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
}
}
+void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ // If the Objective-C message expression is an implicit no-return that
+ // is not modeled in the CFG, set the tracked dataflow values to Unknown.
+ if (objCNoRet.isImplicitNoReturn(ME)) {
+ vals.setAllScratchValues(Unknown);
+ }
+}
+
//------------------------------------------------------------------------====//
// High-level "driver" logic for uninitialized values analysis.
//====------------------------------------------------------------------------//