diff options
Diffstat (limited to 'lib/Checker')
40 files changed, 483 insertions, 215 deletions
diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp index e95a86b..b92f2e7 100644 --- a/lib/Checker/AdjustedReturnValueChecker.cpp +++ b/lib/Checker/AdjustedReturnValueChecker.cpp @@ -14,11 +14,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/ADT/SmallString.h" using namespace clang; diff --git a/lib/Checker/AggExprVisitor.cpp b/lib/Checker/AggExprVisitor.cpp new file mode 100644 index 0000000..343afec --- /dev/null +++ b/lib/Checker/AggExprVisitor.cpp @@ -0,0 +1,55 @@ +//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AggExprVisitor class, which contains lots of boiler +// plate code for evaluating expressions of C++ class type. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/AST/StmtVisitor.h" + +using namespace clang; + +namespace { +class AggExprVisitor : public StmtVisitor<AggExprVisitor> { + SVal DestPtr; + ExplodedNode *Pred; + ExplodedNodeSet &DstSet; + GRExprEngine &Eng; + +public: + AggExprVisitor(SVal dest, ExplodedNode *N, ExplodedNodeSet &dst, + GRExprEngine &eng) + : DestPtr(dest), Pred(N), DstSet(dst), Eng(eng) {} + + void VisitCastExpr(CastExpr *E); + void VisitCXXConstructExpr(CXXConstructExpr *E); +}; +} + +void AggExprVisitor::VisitCastExpr(CastExpr *E) { + switch (E->getCastKind()) { + default: + assert(0 && "Unhandled cast kind"); + case CastExpr::CK_NoOp: + case CastExpr::CK_ConstructorConversion: + Visit(E->getSubExpr()); + break; + } +} + +void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) { + Eng.VisitCXXConstructExpr(E, DestPtr, Pred, DstSet); +} + +void GRExprEngine::VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E)); +} diff --git a/lib/Checker/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp index 74fb06f..746b3f9 100644 --- a/lib/Checker/ArrayBoundChecker.cpp +++ b/lib/Checker/ArrayBoundChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" using namespace clang; diff --git a/lib/Checker/AttrNonNullChecker.cpp b/lib/Checker/AttrNonNullChecker.cpp index 83dc13e..309a74c 100644 --- a/lib/Checker/AttrNonNullChecker.cpp +++ b/lib/Checker/AttrNonNullChecker.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index d6c09a2..810d0fb 100644 --- a/lib/Checker/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -19,9 +19,8 @@ #include "clang/Checker/PathSensitive/GRSimpleAPICheck.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Checker/BugReporter/PathDiagnostic.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/AST/DeclObjC.h" diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 7272b34..12e61af 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/AST/ASTContext.h" #include "clang/Analysis/CFG.h" @@ -1139,12 +1140,9 @@ void EdgeBuilder::addContext(const Stmt *S) { static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N) { - - EdgeBuilder EB(PD, PDB); - const ExplodedNode* NextNode = N->pred_empty() - ? NULL : *(N->pred_begin()); + const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { N = NextNode; NextNode = GetPredecessorNode(N); diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 1d6994b..06cee5b 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/Checker/BugReporter/BugReporter.h" #include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/PathSensitive/ExplodedGraph.h" #include "clang/Checker/PathSensitive/GRState.h" using namespace clang; diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 9a76f6a..3c4a27c 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -16,8 +16,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/BugReporter/PathDiagnostic.h" #include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/Checker/DomainSpecific/CocoaConventions.h" diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index c5bd2eb..dec375e 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangChecker AdjustedReturnValueChecker.cpp + AggExprVisitor.cpp ArrayBoundChecker.cpp AttrNonNullChecker.cpp BasicConstraintManager.cpp @@ -11,16 +12,16 @@ add_clang_library(clangChecker BugReporter.cpp BugReporterVisitors.cpp BuiltinFunctionChecker.cpp - CFRefCount.cpp CallAndMessageChecker.cpp CallInliner.cpp CastToStructChecker.cpp + CFRefCount.cpp CheckDeadStores.cpp + Checker.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp - Checker.cpp CocoaConventions.cpp DereferenceChecker.cpp DivZeroChecker.cpp @@ -38,11 +39,11 @@ add_clang_library(clangChecker MallocChecker.cpp ManagerRegistry.cpp MemRegion.cpp + NoReturnFunctionChecker.cpp NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp - NoReturnFunctionChecker.cpp - OSAtomicChecker.cpp ObjCUnusedIVarsChecker.cpp + OSAtomicChecker.cpp PathDiagnostic.cpp PointerArithChecker.cpp PointerSubChecker.cpp @@ -52,18 +53,18 @@ add_clang_library(clangChecker ReturnPointerRangeChecker.cpp ReturnStackAddressChecker.cpp ReturnUndefChecker.cpp - SVals.cpp - SValuator.cpp SimpleConstraintManager.cpp SimpleSValuator.cpp Store.cpp + SVals.cpp + SValuator.cpp SymbolManager.cpp UndefBranchChecker.cpp UndefCapturedBlockVarChecker.cpp - UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp + UndefResultChecker.cpp UnixAPIChecker.cpp - VLASizeChecker.cpp ValueManager.cpp + VLASizeChecker.cpp ) diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index 32cf753..dd1856c9 100644 --- a/lib/Checker/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/AST/ParentMap.h" -#include "GRExprEngineInternalChecks.h" using namespace clang; diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp index bef5bc2..2c16f89 100644 --- a/lib/Checker/CastToStructChecker.cpp +++ b/lib/Checker/CastToStructChecker.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index 923baf5..efbce61 100644 --- a/lib/Checker/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -36,7 +36,7 @@ class WalkAST : public StmtVisitor<WalkAST> { IdentifierInfo *II_random; enum { num_setids = 6 }; IdentifierInfo *II_setid[num_setids]; - + const bool CheckRand; public: @@ -214,8 +214,8 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS; llvm::SmallVector<SourceRange, 2> ranges; - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + llvm::SmallString<256> sbuf; + llvm::raw_svector_ostream os(sbuf); os << "Variable '" << drCond->getDecl()->getNameAsCString() << "' with floating point type '" << drCond->getType().getAsString() @@ -315,7 +315,7 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType()); if(!FPT) return; - + // Verify that the funcion takes a single argument. if (FPT->getNumArgs() != 1) return; @@ -328,17 +328,16 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { // Verify that the argument is a 'char*'. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) return; - + // Issue a waring. SourceRange R = CE->getCallee()->getSourceRange(); BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'", "Security", "Call to function 'mktemp' is insecure as it always " - "creates or uses insecure temporary file", + "creates or uses insecure temporary file. Use 'mkstemp' instead", CE->getLocStart(), &R, 1); } - //===----------------------------------------------------------------------===// // Check: Linear congruent random number generators should not be used // Originally: <rdar://problem/63371000> @@ -386,20 +385,18 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { return; // Issue a warning. - std::string buf1; - llvm::raw_string_ostream os1(buf1); + llvm::SmallString<256> buf1; + llvm::raw_svector_ostream os1(buf1); os1 << "'" << FD->getNameAsString() << "' is a poor random number generator"; - std::string buf2; - llvm::raw_string_ostream os2(buf2); + llvm::SmallString<256> buf2; + llvm::raw_svector_ostream os2(buf2); os2 << "Function '" << FD->getNameAsString() << "' is obsolete because it implements a poor random number generator." << " Use 'arc4random' instead"; SourceRange R = CE->getCallee()->getSourceRange(); - - BR.EmitBasicReport(os1.str(), "Security", os2.str(), - CE->getLocStart(), &R, 1); + BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1); } //===----------------------------------------------------------------------===// @@ -425,8 +422,7 @@ void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) { "Security", "The 'random' function produces a sequence of values that " "an adversary may be able to predict. Use 'arc4random' " - "instead", - CE->getLocStart(), &R, 1); + "instead", CE->getLocStart(), &R, 1); } //===----------------------------------------------------------------------===// @@ -474,22 +470,20 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { return; // Issue a warning. - std::string buf1; - llvm::raw_string_ostream os1(buf1); + llvm::SmallString<256> buf1; + llvm::raw_svector_ostream os1(buf1); os1 << "Return value is not checked in call to '" << FD->getNameAsString() << "'"; - std::string buf2; - llvm::raw_string_ostream os2(buf2); + llvm::SmallString<256> buf2; + llvm::raw_svector_ostream os2(buf2); os2 << "The return value from the call to '" << FD->getNameAsString() << "' is not checked. If an error occurs in '" << FD->getNameAsString() << "', the following code may execute with unexpected privileges"; SourceRange R = CE->getCallee()->getSourceRange(); - - BR.EmitBasicReport(os1.str(), "Security", os2.str(), - CE->getLocStart(), &R, 1); + BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1); } //===----------------------------------------------------------------------===// diff --git a/lib/Checker/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp index 0cbc408..af74c79 100644 --- a/lib/Checker/DereferenceChecker.cpp +++ b/lib/Checker/DereferenceChecker.cpp @@ -12,11 +12,11 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/Checkers/DereferenceChecker.h" #include "clang/Checker/PathSensitive/Checker.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "GRExprEngineInternalChecks.h" using namespace clang; @@ -29,9 +29,9 @@ public: DereferenceChecker() : BT_null(0), BT_undef(0) {} static void *getTag() { static int tag = 0; return &tag; } void VisitLocation(CheckerContext &C, const Stmt *S, SVal location); - + std::pair<ExplodedNode * const*, ExplodedNode * const*> - getImplicitNodes() const { + getImplicitNodes() const { return std::make_pair(ImplicitNullDerefNodes.data(), ImplicitNullDerefNodes.data() + ImplicitNullDerefNodes.size()); @@ -59,7 +59,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, if (ExplodedNode *N = C.GenerateSink()) { if (!BT_undef) BT_undef = new BuiltinBug("Dereference of undefined pointer value"); - + EnhancedBugReport *report = new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, @@ -68,31 +68,32 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, } return; } - + DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); - - // Check for null dereferences. + + // Check for null dereferences. if (!isa<Loc>(location)) return; - + const GRState *state = C.getState(); const GRState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->Assume(location); - + // The explicit NULL case. if (nullState) { - if (!notNullState) { + if (!notNullState) { // Generate an error node. ExplodedNode *N = C.GenerateSink(nullState); if (!N) return; - + // We know that 'location' cannot be non-null. This is what - // we call an "explicit" null dereference. + // we call an "explicit" null dereference. if (!BT_null) BT_null = new BuiltinBug("Dereference of null pointer"); - + llvm::SmallString<100> buf; + llvm::SmallVector<SourceRange, 2> Ranges; switch (S->getStmtClass()) { case Stmt::UnaryOperatorClass: { @@ -101,10 +102,26 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { llvm::raw_svector_ostream os(buf); - os << "Dereference of null pointer loaded from variable '" - << VD->getName() << '\''; + os << "Dereference of null pointer (loaded from variable '" + << VD->getName() << "')"; + Ranges.push_back(DR->getSourceRange()); } } + break; + } + case Stmt::MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(S); + if (M->isArrow()) + if (DeclRefExpr *DR = + dyn_cast<DeclRefExpr>(M->getBase()->IgnoreParenCasts())) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + llvm::raw_svector_ostream os(buf); + os << "Field access results in a dereference of a null pointer " + "(loaded from variable '" << VD->getName() << "')"; + Ranges.push_back(M->getBase()->getSourceRange()); + } + } + break; } default: break; @@ -117,19 +134,23 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, bugreporter::GetDerefExpr(N)); - + + for (llvm::SmallVectorImpl<SourceRange>::iterator + I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) + report->addRange(*I); + C.EmitReport(report); return; } else { // Otherwise, we have the case where the location could either be // null or not-null. Record the error node as an "implicit" null - // dereference. + // dereference. if (ExplodedNode *N = C.GenerateSink(nullState)) ImplicitNullDerefNodes.push_back(N); } } - + // From this point forward, we know that the location is not null. C.addTransition(notNullState); } diff --git a/lib/Checker/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp index e1346e1..e09a871 100644 --- a/lib/Checker/DivZeroChecker.cpp +++ b/lib/Checker/DivZeroChecker.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp index 671cf89..cc71f85 100644 --- a/lib/Checker/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -10,9 +10,10 @@ // This file defined the Environment and EnvironmentManager classes. // //===----------------------------------------------------------------------===// + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" #include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/ADT/ImmutableMap.h" using namespace clang; diff --git a/lib/Checker/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp index 04c17d6..4fce45b 100644 --- a/lib/Checker/FixedAddressChecker.cpp +++ b/lib/Checker/FixedAddressChecker.cpp @@ -13,8 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/GRBlockCounter.cpp b/lib/Checker/GRBlockCounter.cpp index 3fa3e1e..cd26060 100644 --- a/lib/Checker/GRBlockCounter.cpp +++ b/lib/Checker/GRBlockCounter.cpp @@ -18,7 +18,34 @@ using namespace clang; -typedef llvm::ImmutableMap<unsigned,unsigned> CountMap; +namespace { + +class CountKey { + const StackFrameContext *CallSite; + unsigned BlockID; + +public: + CountKey(const StackFrameContext *CS, unsigned ID) + : CallSite(CS), BlockID(ID) {} + + bool operator==(const CountKey &RHS) const { + return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID); + } + + bool operator<(const CountKey &RHS) const { + return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID) + : (CallSite < RHS.CallSite); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(CallSite); + ID.AddInteger(BlockID); + } +}; + +} + +typedef llvm::ImmutableMap<CountKey, unsigned> CountMap; static inline CountMap GetMap(void* D) { return CountMap(static_cast<CountMap::TreeTy*>(D)); @@ -28,9 +55,10 @@ static inline CountMap::Factory& GetFactory(void* F) { return *static_cast<CountMap::Factory*>(F); } -unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const { +unsigned GRBlockCounter::getNumVisited(const StackFrameContext *CallSite, + unsigned BlockID) const { CountMap M = GetMap(Data); - CountMap::data_type* T = M.lookup(BlockID); + CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID)); return T ? *T : 0; } @@ -43,9 +71,12 @@ GRBlockCounter::Factory::~Factory() { } GRBlockCounter -GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) { - return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID, - BC.getNumVisited(BlockID)+1).getRoot()); +GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, + const StackFrameContext *CallSite, + unsigned BlockID) { + return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), + CountKey(CallSite, BlockID), + BC.getNumVisited(CallSite, BlockID)+1).getRoot()); } GRBlockCounter diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index a9347d0..e4ef6b0 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -126,9 +126,9 @@ void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) { SubEngine.ProcessStmt(E, Builder); } -bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, +bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred, GRBlockCounter BC) { - return SubEngine.ProcessBlockEntrance(Blk, State, BC); + return SubEngine.ProcessBlockEntrance(Blk, Pred, BC); } void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator, @@ -256,7 +256,7 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? - if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter())) + if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter())) GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred); } @@ -265,7 +265,9 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, // Increment the block counter. GRBlockCounter Counter = WList->getBlockCounter(); - Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID()); + Counter = BCounterFactory.IncrementCount(Counter, + Pred->getLocationContext()->getCurrentStackFrame(), + L.getBlock()->getBlockID()); WList->setBlockCounter(Counter); // Process the entrance of the block. diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 3ace552..bab8922 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -13,6 +13,8 @@ // //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/AnalysisManager.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/PathSensitive/GRExprEngineBuilders.h" #include "clang/Checker/PathSensitive/Checker.h" @@ -582,7 +584,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { switch (S->getStmtClass()) { // C++ stuff we don't support yet. - case Stmt::CXXMemberCallExprClass: case Stmt::CXXNamedCastExprClass: case Stmt::CXXStaticCastExprClass: case Stmt::CXXDynamicCastExprClass: @@ -671,6 +672,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXMemberCallExprClass: { + CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S); + VisitCXXMemberCallExpr(MCE, Pred, Dst); + break; + } + // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. @@ -895,6 +902,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; } + case Stmt::ObjCIsaExprClass: + // FIXME: Do something more intelligent with 'x->isa = ...'. + // For now, just ignore the assignment. + return; + case Stmt::ObjCPropertyRefExprClass: case Stmt::ObjCImplicitSetterGetterRefExprClass: // FIXME: Property assignments are lvalues, but not really "locations". @@ -944,10 +956,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, // Block entrance. (Update counters). //===----------------------------------------------------------------------===// -bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*, +bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred, GRBlockCounter BC) { - return BC.getNumVisited(B->getBlockID()) < 3; + return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), + B->getBlockID()) < 3; } //===----------------------------------------------------------------------===// @@ -1328,6 +1341,22 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { if (ReturnedExpr) { SVal RetVal = state->getSVal(ReturnedExpr); state = state->BindExpr(CE, RetVal); + // Clear the return expr GDM. + state = state->remove<ReturnExpr>(); + } + + // Bind the constructed object value to CXXConstructExpr. + if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { + const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx); + // We might not have 'this' region in the binding if we didn't inline + // the ctor call. + SVal ThisV = state->getSVal(ThisR); + loc::MemRegionVal *V = dyn_cast<loc::MemRegionVal>(&ThisV); + if (V) { + SVal ObjVal = state->getSVal(V->getRegion()); + assert(isa<nonloc::LazyCompoundVal>(ObjVal)); + state = state->BindExpr(CCE, ObjVal); + } } B.GenerateNode(state); @@ -2282,6 +2311,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, case CastExpr::CK_AnyPointerToObjCPointerCast: case CastExpr::CK_AnyPointerToBlockPointerCast: case CastExpr::CK_DerivedToBase: + case CastExpr::CK_UncheckedDerivedToBase: // Delegate to SValuator to process. for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { ExplodedNode* N = *I; @@ -2338,8 +2368,10 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet Tmp; if (InitEx) { - if (const CXXConstructExpr *E = dyn_cast<CXXConstructExpr>(InitEx)) { - VisitCXXConstructExpr(E, GetState(Pred)->getLValue(VD, + QualType InitTy = InitEx->getType(); + if (getContext().getLangOptions().CPlusPlus && InitTy->isRecordType()) { + // Delegate expressions of C++ record type evaluation to AggExprVisitor. + VisitAggExpr(InitEx, GetState(Pred)->getLValue(VD, Pred->getLocationContext()), Pred, Dst); return; } else if (VD->getType()->isReferenceType()) @@ -2908,7 +2940,8 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Src; if (Expr *RetE = RS->getRetValue()) { - // Record the returned expression in the state. + // Record the returned expression in the state. It will be used in + // ProcessCallExit to bind the return value to the call expr. { static int Tag = 0; SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag); @@ -3137,6 +3170,10 @@ void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + if (E->isElidable()) { + VisitAggExpr(E->getArg(0), Dest, Pred, Dst); + return; + } const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); @@ -3190,10 +3227,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, Pred->getLocationContext(), E, Builder->getBlock(), Builder->getIndex()); - Type *T = CD->getParent()->getTypeForDecl(); - QualType PT = getContext().getPointerType(QualType(T,0)); - const CXXThisRegion *ThisR = ValMgr.getRegionManager().getCXXThisRegion(PT, - SFC); + const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); CallEnter Loc(E, CD, Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), @@ -3206,6 +3240,91 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, Dst.Add(N); } } + +void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the method type. + const FunctionProtoType *FnType = + MCE->getCallee()->getType()->getAs<FunctionProtoType>(); + assert(FnType && "Method type not available"); + + // Evaluate explicit arguments with a worklist. + CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(), + AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end(); + llvm::SmallVector<CallExprWLItem, 20> WorkList; + WorkList.reserve(AE - AB); + WorkList.push_back(CallExprWLItem(AB, Pred)); + ExplodedNodeSet ArgsEvaluated; + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; + } + + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AB; + bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType(); + + if (VisitAsLvalue) + VisitLValue(*Item.I, Item.N, Tmp); + else + Visit(*Item.I, Item.N, Tmp); + + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } + // Evaluate the implicit object argument. + ExplodedNodeSet AllArgsEvaluated; + const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); + if (!ME) + return; + Expr *ObjArgExpr = ME->getBase(); + for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), + E = ArgsEvaluated.end(); I != E; ++I) { + if (ME->isArrow()) + Visit(ObjArgExpr, *I, AllArgsEvaluated); + else + VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); + } + + const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); + assert(MD && "not a CXXMethodDecl?"); + + if (!MD->isThisDeclarationADefinition()) + // FIXME: conservative method call evaluation. + return; + + const StackFrameContext *SFC = AMgr.getStackFrame(MD, + Pred->getLocationContext(), + MCE, + Builder->getBlock(), + Builder->getIndex()); + const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + CallEnter Loc(MCE, MD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), + E = AllArgsEvaluated.end(); I != E; ++I) { + // Set up 'this' region. + const GRState *state = GetState(*I); + state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); + ExplodedNode *N = Builder->generateNode(Loc, state, *I); + if (N) + Dst.Add(N); + } +} + +const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, + const StackFrameContext *SFC) { + Type *T = D->getParent()->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T,0)); + return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); +} + //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp index 2defbcd..f68e10b 100644 --- a/lib/Checker/GRState.cpp +++ b/lib/Checker/GRState.cpp @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/Analysis/CFG.h" #include "clang/Checker/PathSensitive/GRStateTrait.h" #include "clang/Checker/PathSensitive/GRState.h" #include "clang/Checker/PathSensitive/GRTransferFuncs.h" -#include "llvm/ADT/SmallSet.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -227,6 +227,18 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){ return getPersistentState(NewSt); } +const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) { + GRState::GenericDataMap OldM = state->getGDM(); + GRState::GenericDataMap NewM = GDMFactory.Remove(OldM, Key); + + if (NewM == OldM) + return state; + + GRState NewState = *state; + NewState.GDM = NewM; + return getPersistentState(NewState); +} + //===----------------------------------------------------------------------===// // Utility. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/MacOSXAPIChecker.cpp b/lib/Checker/MacOSXAPIChecker.cpp index 9621e85..bcd96e7 100644 --- a/lib/Checker/MacOSXAPIChecker.cpp +++ b/lib/Checker/MacOSXAPIChecker.cpp @@ -17,7 +17,7 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRStateTrait.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp index a08afc4..a22df30 100644 --- a/lib/Checker/MallocChecker.cpp +++ b/lib/Checker/MallocChecker.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineExperimentalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRState.h" #include "clang/Checker/PathSensitive/GRStateTrait.h" diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 9a26988..9f12ab6 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -13,10 +13,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/AnalysisContext.h" #include "clang/Checker/PathSensitive/MemRegion.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/Support/BumpVector.h" #include "clang/AST/CharUnits.h" -#include "clang/AST/StmtVisitor.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp index e428e2e..9130bfa 100644 --- a/lib/Checker/NSErrorChecker.cpp +++ b/lib/Checker/NSErrorChecker.cpp @@ -16,7 +16,7 @@ //===----------------------------------------------------------------------===// #include "clang/Checker/Checkers/LocalCheckers.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" #include "clang/Checker/Checkers/DereferenceChecker.h" #include "BasicObjCFoundationChecks.h" diff --git a/lib/Checker/NoReturnFunctionChecker.cpp b/lib/Checker/NoReturnFunctionChecker.cpp index 1455d87..12527e0 100644 --- a/lib/Checker/NoReturnFunctionChecker.cpp +++ b/lib/Checker/NoReturnFunctionChecker.cpp @@ -13,17 +13,17 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/Checker.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; namespace { -class NoReturnFunctionChecker : public Checker { +class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> { public: static void *getTag() { static int tag = 0; return &tag; } - virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); }; } @@ -32,48 +32,48 @@ void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) { Eng.registerCheck(new NoReturnFunctionChecker()); } -bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C, - const CallExpr *CE) { +void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C, + const CallExpr *CE) { const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); - SVal L = state->getSVal(Callee); - const FunctionDecl *FD = L.getAsFunctionDecl(); - if (!FD) - return false; - bool BuildSinks = false; + bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn(); - if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>()) - BuildSinks = true; - else if (const IdentifierInfo *II = FD->getIdentifier()) { - // HACK: Some functions are not marked noreturn, and don't return. - // Here are a few hardwired ones. If this takes too long, we can - // potentially cache these results. - BuildSinks - = llvm::StringSwitch<bool>(llvm::StringRef(II->getName())) - .Case("exit", true) - .Case("panic", true) - .Case("error", true) - .Case("Assert", true) - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - .Case("ziperr", true) - .Case("assfail", true) - .Case("db_error", true) - .Case("__assert", true) - .Case("__assert_rtn", true) - .Case("__assert_fail", true) - .Case("dtrace_assfail", true) - .Case("yy_fatal_error", true) - .Case("_XCAssertionFailureHandler", true) - .Case("_DTAssertionFailureHandler", true) - .Case("_TSAssertionFailureHandler", true) - .Default(false); + if (!BuildSinks) { + SVal L = state->getSVal(Callee); + const FunctionDecl *FD = L.getAsFunctionDecl(); + if (!FD) + return; + + if (FD->getAttr<AnalyzerNoReturnAttr>()) + BuildSinks = true; + else if (const IdentifierInfo *II = FD->getIdentifier()) { + // HACK: Some functions are not marked noreturn, and don't return. + // Here are a few hardwired ones. If this takes too long, we can + // potentially cache these results. + BuildSinks + = llvm::StringSwitch<bool>(llvm::StringRef(II->getName())) + .Case("exit", true) + .Case("panic", true) + .Case("error", true) + .Case("Assert", true) + // FIXME: This is just a wrapper around throwing an exception. + // Eventually inter-procedural analysis should handle this easily. + .Case("ziperr", true) + .Case("assfail", true) + .Case("db_error", true) + .Case("__assert", true) + .Case("__assert_rtn", true) + .Case("__assert_fail", true) + .Case("dtrace_assfail", true) + .Case("yy_fatal_error", true) + .Case("_XCAssertionFailureHandler", true) + .Case("_DTAssertionFailureHandler", true) + .Case("_TSAssertionFailureHandler", true) + .Default(false); + } } - - if (!BuildSinks) - return false; - C.GenerateSink(CE); - return true; + if (BuildSinks) + C.GenerateSink(CE); } diff --git a/lib/Checker/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp index 97500d9..963923c 100644 --- a/lib/Checker/PathDiagnostic.cpp +++ b/lib/Checker/PathDiagnostic.cpp @@ -108,8 +108,8 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) P->addRange(Info.getRange(i)); - for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i) - P->addCodeModificationHint(Info.getCodeModificationHint(i)); + for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) + P->addFixItHint(Info.getFixItHint(i)); D->push_front(P); HandlePathDiagnostic(D); diff --git a/lib/Checker/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp index 3d62d0c..ed60c42 100644 --- a/lib/Checker/PointerArithChecker.cpp +++ b/lib/Checker/PointerArithChecker.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp index acc848a..bc0fd24 100644 --- a/lib/Checker/PointerSubChecker.cpp +++ b/lib/Checker/PointerSubChecker.cpp @@ -13,8 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index c2b702a..c97da33 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -536,15 +536,15 @@ public: // First visit the cluster. static_cast<DERIVED*>(this)->VisitCluster(baseR, C->begin(), C->end()); - // Next, visit the region. - static_cast<DERIVED*>(this)->VisitRegion(baseR); + // Next, visit the base region. + static_cast<DERIVED*>(this)->VisitBaseRegion(baseR); } } public: void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C) {} void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) {} - void VisitRegion(const MemRegion *baseR) {} + void VisitBaseRegion(const MemRegion *baseR) {} }; } @@ -580,7 +580,7 @@ public: Ex(ex), Count(count), IS(is) {} void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E); - void VisitRegion(const MemRegion *baseR); + void VisitBaseRegion(const MemRegion *baseR); private: void VisitBinding(SVal V); @@ -627,7 +627,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, } } -void InvalidateRegionsWorker::VisitRegion(const MemRegion *baseR) { +void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { if (IS) { // Symbolic region? Mark that symbol touched by the invalidation. if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) @@ -787,9 +787,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, return ValMgr.makeIntVal(CAT->getSize(), false); } - // Clients can use ordinary variables as if they were arrays. These - // essentially are arrays of size 1. - return ValMgr.makeIntVal(1, false); + // Clients can reinterpret ordinary variables as arrays, possibly of + // another type. The width is rounded down to ensure that an access is + // entirely within bounds. + CharUnits VarSize = getContext().getTypeSizeInChars(T); + CharUnits EleSize = getContext().getTypeSizeInChars(EleTy); + return ValMgr.makeIntVal(VarSize / EleSize, false); } } @@ -963,7 +966,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, Optional<SVal> RegionStoreManager::getBinding(RegionBindings B, const MemRegion *R) { - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return V; return getDefaultBinding(B, R); @@ -1044,7 +1047,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } #endif - if (RTy->isStructureType()) + if (RTy->isStructureType() || RTy->isClassType()) return RetrieveStruct(store, R); // FIXME: Handle unions. @@ -1144,7 +1147,7 @@ SVal RegionStoreManager::RetrieveElement(Store store, const ElementRegion* R) { // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; const MemRegion* superR = R->getSuperRegion(); @@ -1175,7 +1178,7 @@ SVal RegionStoreManager::RetrieveElement(Store store, } // Check if the immediate super region has a direct binding. - if (Optional<SVal> V = getDirectBinding(B, superR)) { + if (const Optional<SVal> &V = getDirectBinding(B, superR)) { if (SymbolRef parentSym = V->getAsSymbol()) return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); @@ -1203,7 +1206,7 @@ SVal RegionStoreManager::RetrieveField(Store store, // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; QualType Ty = R->getValueType(getContext()); @@ -1278,13 +1281,13 @@ SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){ // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; const MemRegion *superR = R->getSuperRegion(); // Check if the super region has a default binding. - if (Optional<SVal> V = getDefaultBinding(B, superR)) { + if (const Optional<SVal> &V = getDefaultBinding(B, superR)) { if (SymbolRef parentSym = V->getAsSymbol()) return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); @@ -1300,7 +1303,7 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { // Check if the region has a binding. RegionBindings B = GetRegionBindings(store); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (const Optional<SVal> &V = getDirectBinding(B, R)) return *V; // Lazily derive a value for the VarRegion. @@ -1313,8 +1316,23 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { return ValMgr.getRegionValueSymbolVal(R); if (isa<GlobalsSpaceRegion>(MS)) { - if (VD->isFileVarDecl()) + if (VD->isFileVarDecl()) { + // Is 'VD' declared constant? If so, retrieve the constant value. + QualType CT = Ctx.getCanonicalType(T); + if (CT.isConstQualified()) { + const Expr *Init = VD->getInit(); + // Do the null check first, as we want to call 'IgnoreParenCasts'. + if (Init) + if (const IntegerLiteral *IL = + dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) { + const nonloc::ConcreteInt &V = ValMgr.makeIntVal(IL); + return ValMgr.getSValuator().EvalCast(V, Init->getType(), + IL->getType()); + } + } + return ValMgr.getRegionValueSymbolVal(R); + } if (T->isIntegerType()) return ValMgr.makeIntVal(0, T); @@ -1337,8 +1355,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(getContext()); - assert(T->isStructureType()); - assert(T->getAsStructureType()->getDecl()->isDefinition()); + assert(T->isStructureType() || T->isClassType()); return ValMgr.makeLazyCompoundVal(store, R); } @@ -1692,8 +1709,8 @@ public: // Called by ClusterAnalysis. void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C); void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E); - void VisitRegion(const MemRegion *baseR); + void VisitBindingKey(BindingKey K); bool UpdatePostponed(); void VisitBinding(SVal V); }; @@ -1730,11 +1747,8 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) { - for ( ; I != E; ++I) { - const MemRegion *R = I->getRegion(); - if (R != baseR) - VisitRegion(R); - } + for ( ; I != E; ++I) + VisitBindingKey(*I); } void RemoveDeadBindingsWorker::VisitBinding(SVal V) { @@ -1762,34 +1776,36 @@ void RemoveDeadBindingsWorker::VisitBinding(SVal V) { SymReaper.markLive(*SI); } -void RemoveDeadBindingsWorker::VisitRegion(const MemRegion *R) { +void RemoveDeadBindingsWorker::VisitBindingKey(BindingKey K) { + const MemRegion *R = K.getRegion(); + // Mark this region "live" by adding it to the worklist. This will cause // use to visit all regions in the cluster (if we haven't visited them // already). - AddToWorkList(R); - - // Mark the symbol for any live SymbolicRegion as "live". This means we - // should continue to track that symbol. - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) - SymReaper.markLive(SymR->getSymbol()); + if (AddToWorkList(R)) { + // Mark the symbol for any live SymbolicRegion as "live". This means we + // should continue to track that symbol. + if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) + SymReaper.markLive(SymR->getSymbol()); + + // For BlockDataRegions, enqueue the VarRegions for variables marked + // with __block (passed-by-reference). + // via BlockDeclRefExprs. + if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) { + for (BlockDataRegion::referenced_vars_iterator + RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); + RI != RE; ++RI) { + if ((*RI)->getDecl()->getAttr<BlocksAttr>()) + AddToWorkList(*RI); + } - // For BlockDataRegions, enqueue the VarRegions for variables marked - // with __block (passed-by-reference). - // via BlockDeclRefExprs. - if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) { - for (BlockDataRegion::referenced_vars_iterator - RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); - RI != RE; ++RI) { - if ((*RI)->getDecl()->getAttr<BlocksAttr>()) - AddToWorkList(*RI); + // No possible data bindings on a BlockDataRegion. + return; } - - // No possible data bindings on a BlockDataRegion. - return; } - // Get the data binding for R (if any). - if (Optional<SVal> V = RM.getBinding(B, R)) + // Visit the data binding for K. + if (const SVal *V = RM.Lookup(B, K)) VisitBinding(*V); } diff --git a/lib/Checker/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp index 949ded5..14edf56 100644 --- a/lib/Checker/ReturnPointerRangeChecker.cpp +++ b/lib/Checker/ReturnPointerRangeChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" using namespace clang; diff --git a/lib/Checker/ReturnStackAddressChecker.cpp b/lib/Checker/ReturnStackAddressChecker.cpp index 9cbabba..35b1cde 100644 --- a/lib/Checker/ReturnStackAddressChecker.cpp +++ b/lib/Checker/ReturnStackAddressChecker.cpp @@ -14,8 +14,8 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Checker/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp index ee25988..52a0b30 100644 --- a/lib/Checker/ReturnUndefChecker.cpp +++ b/lib/Checker/ReturnUndefChecker.cpp @@ -14,10 +14,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "llvm/ADT/SmallString.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" using namespace clang; diff --git a/lib/Checker/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp index 65a46e3..f3a803c 100644 --- a/lib/Checker/SymbolManager.cpp +++ b/lib/Checker/SymbolManager.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "clang/Checker/PathSensitive/SymbolManager.h" +#include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Analysis/AnalysisContext.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Checker/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp index e047b18..9088345 100644 --- a/lib/Checker/UndefBranchChecker.cpp +++ b/lib/Checker/UndefBranchChecker.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/Checker.h" using namespace clang; diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp index a8d7284..b1010c9 100644 --- a/lib/Checker/UndefCapturedBlockVarChecker.cpp +++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp @@ -14,7 +14,7 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/BugReporter/BugType.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Checker/UndefResultChecker.cpp b/lib/Checker/UndefResultChecker.cpp index fb2283a..8b07aed 100644 --- a/lib/Checker/UndefResultChecker.cpp +++ b/lib/Checker/UndefResultChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" using namespace clang; diff --git a/lib/Checker/UndefinedArraySubscriptChecker.cpp b/lib/Checker/UndefinedArraySubscriptChecker.cpp index a2792ad..148629e 100644 --- a/lib/Checker/UndefinedArraySubscriptChecker.cpp +++ b/lib/Checker/UndefinedArraySubscriptChecker.cpp @@ -12,9 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" using namespace clang; diff --git a/lib/Checker/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp index 7c33c1d..6cef60e 100644 --- a/lib/Checker/UndefinedAssignmentChecker.cpp +++ b/lib/Checker/UndefinedAssignmentChecker.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" using namespace clang; @@ -53,27 +53,43 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, if (!N) return; + const char *str = "Assigned value is garbage or undefined"; + if (!BT) - BT = new BuiltinBug("Assigned value is garbage or undefined"); + BT = new BuiltinBug(str); // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + const Expr *ex = 0; - if (AssignE) { - const Expr *ex = 0; + while (AssignE) { + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE)) { + if (B->isCompoundAssignmentOp()) { + const GRState *state = C.getState(); + if (state->getSVal(B->getLHS()).isUndef()) { + str = "The left expression of the compound assignment is an " + "uninitialized value. The computed value will also be garbage"; + ex = B->getLHS(); + break; + } + } - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE)) ex = B->getRHS(); - else if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) { + break; + } + + if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) { const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl()); ex = VD->getInit(); } - if (ex) { - R->addRange(ex->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); - } + + break; } + EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N); + if (ex) { + R->addRange(ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); + } C.EmitReport(R); -} +} diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp index 7ff817a..d75e5d2 100644 --- a/lib/Checker/UnixAPIChecker.cpp +++ b/lib/Checker/UnixAPIChecker.cpp @@ -12,11 +12,10 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/BugReporter/BugType.h" #include "llvm/ADT/StringSwitch.h" -#include "GRExprEngineInternalChecks.h" #include <fcntl.h> using namespace clang; diff --git a/lib/Checker/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp index 51ad1e2..cea9d19 100644 --- a/lib/Checker/VLASizeChecker.cpp +++ b/lib/Checker/VLASizeChecker.cpp @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" +#include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" -#include "clang/Checker/BugReporter/BugReporter.h" using namespace clang; |