diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis')
11 files changed, 1002 insertions, 191 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp index 7de7f39..e7df0a8 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp new file mode 100644 index 0000000..794ff9c --- /dev/null +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.h b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.h new file mode 100644 index 0000000..d503cc1 --- /dev/null +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp index 05c5385..315e543 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp index ff2f777..2d1ca0e 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp +++ b/contrib/llvm/tools/clang/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"; @@ -518,9 +522,9 @@ const char *ConversionSpecifier::toString() const { case ObjCObjArg: return "@"; // FreeBSD specific specifiers. - case bArg: return "b"; - case DArg: return "D"; - case rArg: return "r"; + case FreeBSDbArg: return "b"; + case FreeBSDDArg: return "D"; + case FreeBSDrArg: return "r"; // GlibC specific specifiers. case PrintErrno: return "m"; @@ -528,6 +532,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. //===----------------------------------------------------------------------===// @@ -553,7 +580,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; @@ -568,13 +595,16 @@ 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: - case ConversionSpecifier::rArg: + case ConversionSpecifier::FreeBSDrArg: return true; default: return false; @@ -584,9 +614,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: @@ -600,7 +633,7 @@ bool FormatSpecifier::hasValidLengthModifier() const { case ConversionSpecifier::nArg: case ConversionSpecifier::cArg: case ConversionSpecifier::sArg: - case ConversionSpecifier::rArg: + case ConversionSpecifier::FreeBSDrArg: case ConversionSpecifier::ScanListArg: return true; default: @@ -618,14 +651,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; } @@ -703,10 +737,13 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) case ConversionSpecifier::SArg: return LangOpt.ObjC1 || LangOpt.ObjC2; case ConversionSpecifier::InvalidSpecifier: - case ConversionSpecifier::bArg: - case ConversionSpecifier::DArg: - case ConversionSpecifier::rArg: + case ConversionSpecifier::FreeBSDbArg: + case ConversionSpecifier::FreeBSDDArg: + case ConversionSpecifier::FreeBSDrArg: case ConversionSpecifier::PrintErrno: + case ConversionSpecifier::DArg: + case ConversionSpecifier::OArg: + case ConversionSpecifier::UArg: return false; } llvm_unreachable("Invalid ConversionSpecifier Kind!"); @@ -729,6 +766,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/contrib/llvm/tools/clang/lib/Analysis/ObjCNoReturn.cpp b/contrib/llvm/tools/clang/lib/Analysis/ObjCNoReturn.cpp new file mode 100644 index 0000000..52d844b --- /dev/null +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp index 2b350ce..cacb6cb 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp +++ b/contrib/llvm/tools/clang/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; @@ -197,17 +199,41 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; // FreeBSD format extensions - case 'b': if (LO.FormatExtensions) k = ConversionSpecifier::bArg; break; /* check for int and then char * */ - case 'r': if (LO.FormatExtensions) k = ConversionSpecifier::rArg; break; - case 'y': if (LO.FormatExtensions) k = ConversionSpecifier::iArg; break; - case 'D': if (LO.FormatExtensions) k = ConversionSpecifier::DArg; break; /* check for u_char * pointer and a char * string */ + case 'b': + if (LO.FormatExtensions) + k = ConversionSpecifier::FreeBSDbArg; // int followed by char * + break; + case 'r': + if (LO.FormatExtensions) + k = ConversionSpecifier::FreeBSDrArg; + break; + case 'y': + if (LO.FormatExtensions) + k = ConversionSpecifier::iArg; + break; + // Apple-specific + case 'D': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::DArg; + else if (LO.FormatExtensions) + k = ConversionSpecifier::FreeBSDDArg; // u_char * followed by char * + 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); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); // FreeBSD extension - if (k == ConversionSpecifier::bArg || k == ConversionSpecifier::DArg) + if (k == ConversionSpecifier::FreeBSDbArg || + k == ConversionSpecifier::FreeBSDDArg) argIndex++; if (k == ConversionSpecifier::InvalidSpecifier) { @@ -220,18 +246,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()) @@ -490,9 +517,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. @@ -557,6 +586,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: @@ -566,7 +596,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const { case ConversionSpecifier::GArg: case ConversionSpecifier::aArg: case ConversionSpecifier::AArg: - case ConversionSpecifier::rArg: + case ConversionSpecifier::FreeBSDrArg: return true; default: @@ -581,6 +611,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: @@ -591,7 +622,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() const { case ConversionSpecifier::FArg: case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: - case ConversionSpecifier::rArg: + case ConversionSpecifier::FreeBSDrArg: return true; default: @@ -606,9 +637,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: @@ -633,6 +667,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: @@ -669,8 +704,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: @@ -688,9 +725,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/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp index bb63e2c..11f2ebe 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp index 2942400..574e56a 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp index 5954682..c7f1f62 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp index 858be45..b2e27ca 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/contrib/llvm/tools/clang/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 ∾ 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. //====------------------------------------------------------------------------// |