aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/APSIntType.cpp31
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp20
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp1155
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp541
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp96
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp23
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp42
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp60
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp284
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp98
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp164
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp224
-rw-r--r--lib/StaticAnalyzer/Core/FunctionSummary.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp62
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp92
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp106
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp22
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp459
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp105
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp27
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp105
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h9
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp92
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp88
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp57
28 files changed, 2644 insertions, 1355 deletions
diff --git a/lib/StaticAnalyzer/Core/APSIntType.cpp b/lib/StaticAnalyzer/Core/APSIntType.cpp
index 884b0faa9e..c7e9526821 100644
--- a/lib/StaticAnalyzer/Core/APSIntType.cpp
+++ b/lib/StaticAnalyzer/Core/APSIntType.cpp
@@ -13,20 +13,31 @@ using namespace clang;
using namespace ento;
APSIntType::RangeTestResultKind
-APSIntType::testInRange(const llvm::APSInt &Value) const {
+APSIntType::testInRange(const llvm::APSInt &Value,
+ bool AllowSignConversions) const {
+
// Negative numbers cannot be losslessly converted to unsigned type.
- if (IsUnsigned && Value.isSigned() && Value.isNegative())
+ if (IsUnsigned && !AllowSignConversions &&
+ Value.isSigned() && Value.isNegative())
return RTR_Below;
- // Signed integers can be converted to signed integers of the same width
- // or (if positive) unsigned integers with one fewer bit.
- // Unsigned integers can be converted to unsigned integers of the same width
- // or signed integers with one more bit.
unsigned MinBits;
- if (Value.isSigned())
- MinBits = Value.getMinSignedBits() - IsUnsigned;
- else
- MinBits = Value.getActiveBits() + !IsUnsigned;
+ if (AllowSignConversions) {
+ if (Value.isSigned() && !IsUnsigned)
+ MinBits = Value.getMinSignedBits();
+ else
+ MinBits = Value.getActiveBits();
+
+ } else {
+ // Signed integers can be converted to signed integers of the same width
+ // or (if positive) unsigned integers with one fewer bit.
+ // Unsigned integers can be converted to unsigned integers of the same width
+ // or signed integers with one more bit.
+ if (Value.isSigned())
+ MinBits = Value.getMinSignedBits() - IsUnsigned;
+ else
+ MinBits = Value.getActiveBits() + !IsUnsigned;
+ }
if (MinBits <= BitWidth)
return RTR_Within;
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 011d4c09a2..747b73c416 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -25,7 +25,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
/*AddImplicitDtors=*/true,
/*AddInitializers=*/true,
Options.includeTemporaryDtorsInCFG(),
- Options.shouldSynthesizeBodies()),
+ Options.shouldSynthesizeBodies(),
+ Options.shouldConditionalizeStaticInitializers()),
Ctx(ctx),
Diags(diags),
LangOpts(lang),
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index dca68f71ab..ae707395fc 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -74,7 +74,7 @@ AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
static const char *ModeKey = "c++-inlining";
StringRef ModeStr(Config.GetOrCreateValue(ModeKey,
- "constructors").getValue());
+ "destructors").getValue());
CXXInlineableMemberKind &MutableMode =
const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
@@ -134,6 +134,13 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() {
/*Default=*/true);
}
+bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() {
+ return getBooleanOption(InlineCXXContainerCtorsAndDtors,
+ "c++-container-inlining",
+ /*Default=*/false);
+}
+
+
bool AnalyzerOptions::mayInlineObjCMethod() {
return getBooleanOption(ObjCInliningMode,
"objc-inlining",
@@ -158,6 +165,12 @@ bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
/* Default = */ true);
}
+bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
+ return getBooleanOption(SuppressFromCXXStandardLibrary,
+ "suppress-c++-stdlib",
+ /* Default = */ false);
+}
+
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
@@ -236,3 +249,8 @@ bool AnalyzerOptions::shouldSynthesizeBodies() {
bool AnalyzerOptions::shouldPrunePaths() {
return getBooleanOption("prune-paths", true);
}
+
+bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
+ return getBooleanOption("cfg-conditional-static-initializers", true);
+}
+
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 0729b5e842..a85235c3e4 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "BugReporter"
+
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -29,12 +31,19 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
#include <queue>
using namespace clang;
using namespace ento;
+STATISTIC(MaxBugClassSize,
+ "The maximum number of bug reports in the same equivalence class");
+STATISTIC(MaxValidBugClassSize,
+ "The maximum number of bug reports in the same equivalence class "
+ "where at least one report is valid (not suppressed)");
+
BugReporterVisitor::~BugReporterVisitor() {}
void BugReporterContext::anchor() {}
@@ -43,77 +52,22 @@ void BugReporterContext::anchor() {}
// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===//
-static inline const Stmt *GetStmt(const ProgramPoint &P) {
- if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
- return SP->getStmt();
- if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
- return BE->getSrc()->getTerminator();
- if (Optional<CallEnter> CE = P.getAs<CallEnter>())
- return CE->getCallExpr();
- if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
- return CEE->getCalleeContext()->getCallSite();
-
- return 0;
-}
-
-static inline const ExplodedNode*
-GetPredecessorNode(const ExplodedNode *N) {
- return N->pred_empty() ? NULL : *(N->pred_begin());
-}
-
-static inline const ExplodedNode*
-GetSuccessorNode(const ExplodedNode *N) {
- return N->succ_empty() ? NULL : *(N->succ_begin());
-}
-
static const Stmt *GetPreviousStmt(const ExplodedNode *N) {
- for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N))
- if (const Stmt *S = GetStmt(N->getLocation()))
- return S;
-
- return 0;
-}
-
-static const Stmt *GetNextStmt(const ExplodedNode *N) {
- for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N))
- if (const Stmt *S = GetStmt(N->getLocation())) {
- // Check if the statement is '?' or '&&'/'||'. These are "merges",
- // not actual statement points.
- switch (S->getStmtClass()) {
- case Stmt::ChooseExprClass:
- case Stmt::BinaryConditionalOperatorClass: continue;
- case Stmt::ConditionalOperatorClass: continue;
- case Stmt::BinaryOperatorClass: {
- BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
- if (Op == BO_LAnd || Op == BO_LOr)
- continue;
- break;
- }
- default:
- break;
- }
+ for (N = N->getFirstPred(); N; N = N->getFirstPred())
+ if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
return S;
- }
return 0;
}
static inline const Stmt*
GetCurrentOrPreviousStmt(const ExplodedNode *N) {
- if (const Stmt *S = GetStmt(N->getLocation()))
+ if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
return S;
return GetPreviousStmt(N);
}
-static inline const Stmt*
-GetCurrentOrNextStmt(const ExplodedNode *N) {
- if (const Stmt *S = GetStmt(N->getLocation()))
- return S;
-
- return GetNextStmt(N);
-}
-
//===----------------------------------------------------------------------===//
// Diagnostic cleanup.
//===----------------------------------------------------------------------===//
@@ -189,10 +143,16 @@ static void removeRedundantMsgs(PathPieces &path) {
}
}
+/// A map from PathDiagnosticPiece to the LocationContext of the inlined
+/// function call it represents.
+typedef llvm::DenseMap<const PathPieces *, const LocationContext *>
+ LocationContextMap;
+
/// Recursively scan through a path and prune out calls and macros pieces
/// that aren't needed. Return true if afterwards the path contains
/// "interesting stuff" which means it shouldn't be pruned from the parent path.
-bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) {
+static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
+ LocationContextMap &LCM) {
bool containsSomethingInteresting = false;
const unsigned N = pieces.size();
@@ -213,13 +173,13 @@ bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) {
case PathDiagnosticPiece::Call: {
PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
// Check if the location context is interesting.
- assert(LocationContextMap.count(call));
- if (R->isInteresting(LocationContextMap[call])) {
+ assert(LCM.count(&call->path));
+ if (R->isInteresting(LCM[&call->path])) {
containsSomethingInteresting = true;
break;
}
- if (!RemoveUnneededCalls(call->path, R))
+ if (!removeUnneededCalls(call->path, R, LCM))
continue;
containsSomethingInteresting = true;
@@ -227,7 +187,7 @@ bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) {
}
case PathDiagnosticPiece::Macro: {
PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece);
- if (!RemoveUnneededCalls(macro->subPieces, R))
+ if (!removeUnneededCalls(macro->subPieces, R, LCM))
continue;
containsSomethingInteresting = true;
break;
@@ -290,19 +250,14 @@ static void adjustCallLocations(PathPieces &Pieces,
// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
-typedef llvm::DenseMap<const ExplodedNode*,
-const ExplodedNode*> NodeBackMap;
-
namespace {
class NodeMapClosure : public BugReport::NodeResolver {
- NodeBackMap& M;
+ InterExplodedGraphMap &M;
public:
- NodeMapClosure(NodeBackMap *m) : M(*m) {}
- ~NodeMapClosure() {}
+ NodeMapClosure(InterExplodedGraphMap &m) : M(m) {}
const ExplodedNode *getOriginalNode(const ExplodedNode *N) {
- NodeBackMap::iterator I = M.find(N);
- return I == M.end() ? 0 : I->second;
+ return M.lookup(N);
}
};
@@ -314,7 +269,7 @@ public:
const LocationContext *LC;
PathDiagnosticBuilder(GRBugReporter &br,
- BugReport *r, NodeBackMap *Backmap,
+ BugReport *r, InterExplodedGraphMap &Backmap,
PathDiagnosticConsumer *pdc)
: BugReporterContext(br),
R(r), PDC(pdc), NMC(Backmap), LC(r->getErrorNode()->getLocationContext())
@@ -351,7 +306,7 @@ public:
PathDiagnosticLocation
PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode *N) {
- if (const Stmt *S = GetNextStmt(N))
+ if (const Stmt *S = PathDiagnosticLocation::getNextStmt(N))
return PathDiagnosticLocation(S, getSourceManager(), LC);
return PathDiagnosticLocation::createDeclEnd(N->getLocationContext(),
@@ -562,6 +517,7 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM);
static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
+ LocationContextMap &LCM,
ArrayRef<BugReporterVisitor *> visitors) {
SourceManager& SMgr = PDB.getSourceManager();
@@ -574,7 +530,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
while (NextNode) {
N = NextNode;
PDB.LC = N->getLocationContext();
- NextNode = GetPredecessorNode(N);
+ NextNode = N->getFirstPred();
ProgramPoint P = N->getLocation();
@@ -582,8 +538,8 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
PathDiagnosticCallPiece *C =
PathDiagnosticCallPiece::construct(N, *CE, SMgr);
- GRBugReporter& BR = PDB.getBugReporter();
- BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ // Record the mapping from call piece to LocationContext.
+ LCM[&C->path] = CE->getCalleeContext();
PD.getActivePath().push_front(C);
PD.pushActivePath(&C->path);
CallStack.push_back(StackDiagPair(C, N));
@@ -606,8 +562,8 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
} else {
const Decl *Caller = CE->getLocationContext()->getDecl();
C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
- GRBugReporter& BR = PDB.getBugReporter();
- BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ // Record the mapping from call piece to LocationContext.
+ LCM[&C->path] = CE->getCalleeContext();
}
C->setCallee(*CE, SMgr);
@@ -636,7 +592,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
case Stmt::GotoStmtClass:
case Stmt::IndirectGotoStmtClass: {
- const Stmt *S = GetNextStmt(N);
+ const Stmt *S = PathDiagnosticLocation::getNextStmt(N);
if (!S)
break;
@@ -925,6 +881,50 @@ public:
bool isDead() const { return IsDead; }
};
+static PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L,
+ const LocationContext *LC,
+ bool firstCharOnly = false) {
+ if (const Stmt *S = L.asStmt()) {
+ const Stmt *Original = S;
+ while (1) {
+ // Adjust the location for some expressions that are best referenced
+ // by one of their subexpressions.
+ switch (S->getStmtClass()) {
+ default:
+ break;
+ case Stmt::ParenExprClass:
+ case Stmt::GenericSelectionExprClass:
+ S = cast<Expr>(S)->IgnoreParens();
+ firstCharOnly = true;
+ continue;
+ case Stmt::BinaryConditionalOperatorClass:
+ case Stmt::ConditionalOperatorClass:
+ S = cast<AbstractConditionalOperator>(S)->getCond();
+ firstCharOnly = true;
+ continue;
+ case Stmt::ChooseExprClass:
+ S = cast<ChooseExpr>(S)->getCond();
+ firstCharOnly = true;
+ continue;
+ case Stmt::BinaryOperatorClass:
+ S = cast<BinaryOperator>(S)->getLHS();
+ firstCharOnly = true;
+ continue;
+ }
+
+ break;
+ }
+
+ if (S != Original)
+ L = PathDiagnosticLocation(S, L.getManager(), LC);
+ }
+
+ if (firstCharOnly)
+ L = PathDiagnosticLocation::createSingleLocation(L);
+
+ return L;
+}
+
class EdgeBuilder {
std::vector<ContextLocation> CLocs;
typedef std::vector<ContextLocation>::iterator iterator;
@@ -939,53 +939,12 @@ class EdgeBuilder {
PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L);
- PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L,
- bool firstCharOnly = false) {
- if (const Stmt *S = L.asStmt()) {
- const Stmt *Original = S;
- while (1) {
- // Adjust the location for some expressions that are best referenced
- // by one of their subexpressions.
- switch (S->getStmtClass()) {
- default:
- break;
- case Stmt::ParenExprClass:
- case Stmt::GenericSelectionExprClass:
- S = cast<Expr>(S)->IgnoreParens();
- firstCharOnly = true;
- continue;
- case Stmt::BinaryConditionalOperatorClass:
- case Stmt::ConditionalOperatorClass:
- S = cast<AbstractConditionalOperator>(S)->getCond();
- firstCharOnly = true;
- continue;
- case Stmt::ChooseExprClass:
- S = cast<ChooseExpr>(S)->getCond();
- firstCharOnly = true;
- continue;
- case Stmt::BinaryOperatorClass:
- S = cast<BinaryOperator>(S)->getLHS();
- firstCharOnly = true;
- continue;
- }
-
- break;
- }
-
- if (S != Original)
- L = PathDiagnosticLocation(S, L.getManager(), PDB.LC);
- }
-
- if (firstCharOnly)
- L = PathDiagnosticLocation::createSingleLocation(L);
- return L;
- }
void popLocation() {
if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) {
// For contexts, we only one the first character as the range.
- rawAddEdge(cleanUpLocation(CLocs.back(), true));
+ rawAddEdge(cleanUpLocation(CLocs.back(), PDB.LC, true));
}
CLocs.pop_back();
}
@@ -1022,7 +981,8 @@ public:
PrevLoc = PathDiagnosticLocation();
}
- void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false);
+ void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false,
+ bool IsPostJump = false);
void rawAddEdge(PathDiagnosticLocation NewLoc);
@@ -1098,8 +1058,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
return;
}
- const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc);
- const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc);
+ const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc, PDB.LC);
+ const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc, PDB.LC);
if (PrevLocClean.asLocation().isInvalid()) {
PrevLoc = NewLoc;
@@ -1118,7 +1078,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
PrevLoc = NewLoc;
}
-void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
+void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd,
+ bool IsPostJump) {
if (!alwaysAdd && NewLoc.asLocation().isMacroID())
return;
@@ -1131,13 +1092,14 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
// Is the top location context the same as the one for the new location?
if (TopContextLoc == CLoc) {
if (alwaysAdd) {
- if (IsConsumedExpr(TopContextLoc) &&
- !IsControlFlowExpr(TopContextLoc.asStmt()))
- TopContextLoc.markDead();
+ if (IsConsumedExpr(TopContextLoc))
+ TopContextLoc.markDead();
rawAddEdge(NewLoc);
}
+ if (IsPostJump)
+ TopContextLoc.markDead();
return;
}
@@ -1145,13 +1107,13 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
if (alwaysAdd) {
rawAddEdge(NewLoc);
- if (IsConsumedExpr(CLoc) && !IsControlFlowExpr(CLoc.asStmt())) {
- CLocs.push_back(ContextLocation(CLoc, true));
+ if (IsConsumedExpr(CLoc)) {
+ CLocs.push_back(ContextLocation(CLoc, /*IsDead=*/true));
return;
}
}
- CLocs.push_back(CLoc);
+ CLocs.push_back(ContextLocation(CLoc, /*IsDead=*/IsPostJump));
return;
}
@@ -1305,6 +1267,7 @@ static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
switch (Term->getStmtClass()) {
case Stmt::ForStmtClass:
case Stmt::WhileStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
break;
default:
// Note that we intentionally do not include do..while here.
@@ -1335,7 +1298,7 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
if (!isContainedByStmt(PM, Term, S))
return S;
}
- N = GetPredecessorNode(N);
+ N = N->getFirstPred();
}
return 0;
}
@@ -1350,6 +1313,11 @@ static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
LoopBody = FS->getBody();
break;
}
+ case Stmt::ObjCForCollectionStmtClass: {
+ const ObjCForCollectionStmt *FC = cast<ObjCForCollectionStmt>(Term);
+ LoopBody = FC->getBody();
+ break;
+ }
case Stmt::WhileStmtClass:
LoopBody = cast<WhileStmt>(Term)->getBody();
break;
@@ -1366,6 +1334,7 @@ static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
+ LocationContextMap &LCM,
ArrayRef<BugReporterVisitor *> visitors) {
EdgeBuilder EB(PD, PDB);
const SourceManager& SM = PDB.getSourceManager();
@@ -1375,7 +1344,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
- NextNode = GetPredecessorNode(N);
+ NextNode = N->getFirstPred();
ProgramPoint P = N->getLocation();
do {
@@ -1396,10 +1365,9 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticCallPiece *C =
PathDiagnosticCallPiece::construct(N, *CE, SM);
- GRBugReporter& BR = PDB.getBugReporter();
- BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ LCM[&C->path] = CE->getCalleeContext();
- EB.addEdge(C->callReturn, true);
+ EB.addEdge(C->callReturn, /*AlwaysAdd=*/true, /*IsPostJump=*/true);
EB.flushLocations();
PD.getActivePath().push_front(C);
@@ -1434,8 +1402,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
} else {
const Decl *Caller = CE->getLocationContext()->getDecl();
C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
- GRBugReporter& BR = PDB.getBugReporter();
- BR.addCallPieceLocationContextPair(C, CE->getCalleeContext());
+ LCM[&C->path] = CE->getCalleeContext();
}
C->setCallee(*CE, SM);
@@ -1563,6 +1530,458 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
return PDB.getBugReport()->isValid();
}
+/// \brief Adds a sanitized control-flow diagnostic edge to a path.
+static void addEdgeToPath(PathPieces &path,
+ PathDiagnosticLocation &PrevLoc,
+ PathDiagnosticLocation NewLoc,
+ const LocationContext *LC) {
+ if (!NewLoc.isValid())
+ return;
+
+ SourceLocation NewLocL = NewLoc.asLocation();
+ if (NewLocL.isInvalid() || NewLocL.isMacroID())
+ return;
+
+ if (!PrevLoc.isValid()) {
+ PrevLoc = NewLoc;
+ return;
+ }
+
+ // FIXME: ignore intra-macro edges for now.
+ if (NewLoc.asLocation().getExpansionLoc() ==
+ PrevLoc.asLocation().getExpansionLoc())
+ return;
+
+ path.push_front(new PathDiagnosticControlFlowPiece(NewLoc,
+ PrevLoc));
+ PrevLoc = NewLoc;
+}
+
+static bool
+GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
+ PathDiagnosticBuilder &PDB,
+ const ExplodedNode *N,
+ LocationContextMap &LCM,
+ ArrayRef<BugReporterVisitor *> visitors) {
+
+ BugReport *report = PDB.getBugReport();
+ const SourceManager& SM = PDB.getSourceManager();
+ StackDiagVector CallStack;
+ InterestingExprs IE;
+
+ // Record the last location for a given visited stack frame.
+ llvm::DenseMap<const StackFrameContext *, PathDiagnosticLocation>
+ PrevLocMap;
+
+ const ExplodedNode *NextNode = N->getFirstPred();
+ while (NextNode) {
+ N = NextNode;
+ NextNode = N->getFirstPred();
+ ProgramPoint P = N->getLocation();
+ const LocationContext *LC = N->getLocationContext();
+ assert(!LCM[&PD.getActivePath()] || LCM[&PD.getActivePath()] == LC);
+ LCM[&PD.getActivePath()] = LC;
+ PathDiagnosticLocation &PrevLoc = PrevLocMap[LC->getCurrentStackFrame()];
+
+ do {
+ if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
+ // For expressions, make sure we propagate the
+ // interesting symbols correctly.
+ if (const Expr *Ex = PS->getStmtAs<Expr>())
+ reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
+ N->getState().getPtr(), Ex,
+ N->getLocationContext());
+
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation(PS->getStmt(), SM, LC);
+ addEdgeToPath(PD.getActivePath(), PrevLoc, L, LC);
+ break;
+ }
+
+ // Have we encountered an exit from a function call?
+ if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
+ const Stmt *S = CE->getCalleeContext()->getCallSite();
+ // Propagate the interesting symbols accordingly.
+ if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
+ reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
+ N->getState().getPtr(), Ex,
+ N->getLocationContext());
+ }
+
+ // We are descending into a call (backwards). Construct
+ // a new call piece to contain the path pieces for that call.
+ PathDiagnosticCallPiece *C =
+ PathDiagnosticCallPiece::construct(N, *CE, SM);
+
+ // Record the location context for this call piece.
+ LCM[&C->path] = CE->getCalleeContext();
+
+ // Add the edge to the return site.
+ addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, LC);
+
+ // Make the contents of the call the active path for now.
+ PD.pushActivePath(&C->path);
+ CallStack.push_back(StackDiagPair(C, N));
+ break;
+ }
+
+ // Have we encountered an entrance to a call? It may be
+ // the case that we have not encountered a matching
+ // call exit before this point. This means that the path
+ // terminated within the call itself.
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
+ // Add an edge to the start of the function.
+ const Decl *D = CE->getCalleeContext()->getDecl();
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createBegin(D, SM), LC);
+
+ // Did we visit an entire call?
+ bool VisitedEntireCall = PD.isWithinCall();
+ PD.popActivePath();
+
+ PathDiagnosticCallPiece *C;
+ if (VisitedEntireCall) {
+ C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front());
+ } else {
+ const Decl *Caller = CE->getLocationContext()->getDecl();
+ C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
+ LCM[&C->path] = CE->getCalleeContext();
+ }
+ C->setCallee(*CE, SM);
+
+ if (!CallStack.empty()) {
+ assert(CallStack.back().first == C);
+ CallStack.pop_back();
+ }
+ break;
+ }
+
+ // Block edges.
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
+ // Does this represent entering a call? If so, look at propagating
+ // interesting symbols across call boundaries.
+ if (NextNode) {
+ const LocationContext *CallerCtx = NextNode->getLocationContext();
+ const LocationContext *CalleeCtx = PDB.LC;
+ if (CallerCtx != CalleeCtx) {
+ reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
+ N->getState().getPtr(),
+ CalleeCtx, CallerCtx);
+ }
+ }
+
+ // Are we jumping to the head of a loop? Add a special diagnostic.
+ if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
+ PathDiagnosticLocation L(Loop, SM, PDB.LC);
+ const CompoundStmt *CS = NULL;
+
+ if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(FS->getBody());
+ else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
+ CS = dyn_cast<CompoundStmt>(WS->getBody());
+
+ PathDiagnosticEventPiece *p =
+ new PathDiagnosticEventPiece(L, "Looping back to the head "
+ "of the loop");
+ p->setPrunable(true);
+
+ addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC);
+ PD.getActivePath().push_front(p);