Update Clang for rebase to r212749.
This also fixes a small issue with arm_neon.h not being generated always.
Includes a cherry-pick of:
r213450 - fixes mac-specific header issue
r213126 - removes a default -Bsymbolic on Android
Change-Id: I2a790a0f5d3b2aab11de596fc3a74e7cbc99081d
diff --git a/lib/StaticAnalyzer/Checkers/Android.mk b/lib/StaticAnalyzer/Checkers/Android.mk
index bb2a539..ab3da80 100644
--- a/lib/StaticAnalyzer/Checkers/Android.mk
+++ b/lib/StaticAnalyzer/Checkers/Android.mk
@@ -70,6 +70,7 @@
StackAddrEscapeChecker.cpp \
StreamChecker.cpp \
TaintTesterChecker.cpp \
+ TestAfterDivZeroChecker.cpp \
TraversalChecker.cpp \
UndefBranchChecker.cpp \
UndefCapturedBlockVarChecker.cpp \
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index d36679d..3fd5576 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -523,16 +523,17 @@
}
//===----------------------------------------------------------------------===//
-// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
+// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
//===----------------------------------------------------------------------===//
namespace {
class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable std::unique_ptr<APIMisuse> BT;
- mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
+ mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
public:
CFRetainReleaseChecker()
- : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr) {}
+ : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
+ Autorelease(nullptr) {}
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
@@ -554,13 +555,15 @@
Retain = &Ctx.Idents.get("CFRetain");
Release = &Ctx.Idents.get("CFRelease");
MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
+ Autorelease = &Ctx.Idents.get("CFAutorelease");
BT.reset(new APIMisuse(
- this, "null passed to CFRetain/CFRelease/CFMakeCollectable"));
+ this, "null passed to CF memory management function"));
}
- // Check if we called CFRetain/CFRelease/CFMakeCollectable.
+ // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
const IdentifierInfo *FuncII = FD->getIdentifier();
- if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
+ if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
+ FuncII == Autorelease))
return;
// FIXME: The rest of this just checks that the argument is non-null.
@@ -597,6 +600,8 @@
description = "Null pointer argument in call to CFRelease";
else if (FuncII == MakeCollectable)
description = "Null pointer argument in call to CFMakeCollectable";
+ else if (FuncII == Autorelease)
+ description = "Null pointer argument in call to CFAutorelease";
else
llvm_unreachable("impossible case");
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 8e7a839..9fb22ec 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -64,6 +64,7 @@
StackAddrEscapeChecker.cpp
StreamChecker.cpp
TaintTesterChecker.cpp
+ TestAfterDivZeroChecker.cpp
TraversalChecker.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index a457b44..44eb641 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -124,6 +124,10 @@
HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables)">,
DescFile<"CallAndMessageChecker.cpp">;
+def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">,
+ HelpText<"Check for division by variable that is later compared against 0. Either the comparison is useless or there is division by zero.">,
+ DescFile<"TestAfterDivZeroChecker.cpp">;
+
} // end "alpha.core"
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index efdc213..4ee0223 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -126,7 +126,7 @@
os << "Array access";
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext());
+ State.get(), N->getLocationContext());
os << " results in a null pointer dereference";
break;
}
@@ -134,7 +134,7 @@
os << "Dereference of null pointer";
const UnaryOperator *U = cast<UnaryOperator>(S);
AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
- State.getPtr(), N->getLocationContext(), true);
+ State.get(), N->getLocationContext(), true);
break;
}
case Stmt::MemberExprClass: {
@@ -143,7 +143,7 @@
os << "Access to field '" << M->getMemberNameInfo()
<< "' results in a dereference of a null pointer";
AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext(), true);
+ State.get(), N->getLocationContext(), true);
}
break;
}
@@ -152,7 +152,7 @@
os << "Access to instance variable '" << *IV->getDecl()
<< "' results in a dereference of a null pointer";
AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext(), true);
+ State.get(), N->getLocationContext(), true);
break;
}
default:
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 0c130fe..eb699d6 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -2340,14 +2340,27 @@
// Get the SourceLocation for the allocation site.
// FIXME: This will crash the analyzer if an allocation comes from an
- // implicit call. (Currently there are no such allocations in Cocoa, though.)
- const Stmt *AllocStmt;
+ // implicit call (ex: a destructor call).
+ // (Currently there are no such allocations in Cocoa, though.)
+ const Stmt *AllocStmt = 0;
ProgramPoint P = AllocNode->getLocation();
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocStmt = Exit->getCalleeContext()->getCallSite();
- else
- AllocStmt = P.castAs<PostStmt>().getStmt();
- assert(AllocStmt && "All allocations must come from explicit calls");
+ else {
+ // We are going to get a BlockEdge when the leak and allocation happen in
+ // different, non-nested frames (contexts). For example, the case where an
+ // allocation happens in a block that captures a reference to it and
+ // that reference is overwritten/dropped by another call to the block.
+ if (Optional<BlockEdge> Edge = P.getAs<BlockEdge>()) {
+ if (Optional<CFGStmt> St = Edge->getDst()->front().getAs<CFGStmt>()) {
+ AllocStmt = St->getStmt();
+ }
+ }
+ else {
+ AllocStmt = P.castAs<PostStmt>().getStmt();
+ }
+ }
+ assert(AllocStmt && "Cannot find allocation statement");
PathDiagnosticLocation AllocLocation =
PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
diff --git a/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
new file mode 100644
index 0000000..a740b7c
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -0,0 +1,264 @@
+//== TestAfterDivZeroChecker.cpp - Test after division by zero checker --*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines TestAfterDivZeroChecker, a builtin check that performs checks
+// for division by zero where the division occurs before comparison with zero.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/FoldingSet.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class ZeroState {
+private:
+ SymbolRef ZeroSymbol;
+ unsigned BlockID;
+ const StackFrameContext *SFC;
+
+public:
+ ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC)
+ : ZeroSymbol(S), BlockID(B), SFC(SFC) {}
+
+ const StackFrameContext *getStackFrameContext() const { return SFC; }
+
+ bool operator==(const ZeroState &X) const {
+ return BlockID == X.BlockID && SFC == X.SFC && ZeroSymbol == X.ZeroSymbol;
+ }
+
+ bool operator<(const ZeroState &X) const {
+ if (BlockID != X.BlockID)
+ return BlockID < X.BlockID;
+ if (SFC != X.SFC)
+ return SFC < X.SFC;
+ return ZeroSymbol < X.ZeroSymbol;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(BlockID);
+ ID.AddPointer(SFC);
+ ID.AddPointer(ZeroSymbol);
+ }
+};
+
+class DivisionBRVisitor : public BugReporterVisitorImpl<DivisionBRVisitor> {
+private:
+ SymbolRef ZeroSymbol;
+ const StackFrameContext *SFC;
+ bool Satisfied = false;
+
+public:
+ DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC)
+ : ZeroSymbol(ZeroSymbol), SFC(SFC) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ ID.Add(ZeroSymbol);
+ ID.Add(SFC);
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+};
+
+class TestAfterDivZeroChecker
+ : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
+ check::EndFunction> {
+ mutable std::unique_ptr<BuiltinBug> DivZeroBug;
+ void reportBug(SVal Val, CheckerContext &C) const;
+
+public:
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
+ void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
+ void checkEndFunction(CheckerContext &C) const;
+ void setDivZeroMap(SVal Var, CheckerContext &C) const;
+ bool hasDivZeroMap(SVal Var, const CheckerContext &C) const;
+ bool isZero(SVal S, CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState)
+
+PathDiagnosticPiece *DivisionBRVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ if (Satisfied)
+ return nullptr;
+
+ const Expr *E = nullptr;
+
+ if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
+ if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
+ BinaryOperator::Opcode Op = BO->getOpcode();
+ if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
+ Op == BO_RemAssign) {
+ E = BO->getRHS();
+ }
+ }
+
+ if (!E)
+ return nullptr;
+
+ ProgramStateRef State = Succ->getState();
+ SVal S = State->getSVal(E, Succ->getLocationContext());
+ if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) {
+ Satisfied = true;
+
+ // Construct a new PathDiagnosticPiece.
+ ProgramPoint P = Succ->getLocation();
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::create(P, BRC.getSourceManager());
+
+ if (!L.isValid() || !L.asLocation().isValid())
+ return nullptr;
+
+ return new PathDiagnosticEventPiece(
+ L, "Division with compared value made here");
+ }
+
+ return nullptr;
+}
+
+bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const {
+ Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
+
+ if (!DSV)
+ return false;
+
+ ConstraintManager &CM = C.getConstraintManager();
+ return !CM.assume(C.getState(), *DSV, true);
+}
+
+void TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &C) const {
+ SymbolRef SR = Var.getAsSymbol();
+ if (!SR)
+ return;
+
+ ProgramStateRef State = C.getState();
+ State =
+ State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame()));
+ C.addTransition(State);
+}
+
+bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
+ const CheckerContext &C) const {
+ SymbolRef SR = Var.getAsSymbol();
+ if (!SR)
+ return false;
+
+ ZeroState ZS(SR, C.getBlockID(), C.getStackFrame());
+ return C.getState()->contains<DivZeroMap>(ZS);
+}
+
+void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
+ if (ExplodedNode *N = C.generateSink(C.getState())) {
+ if (!DivZeroBug)
+ DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
+
+ BugReport *R =
+ new BugReport(*DivZeroBug, "Value being compared against zero has "
+ "already been used for division",
+ N);
+
+ R->addVisitor(new DivisionBRVisitor(Val.getAsSymbol(), C.getStackFrame()));
+ C.emitReport(R);
+ }
+}
+
+void TestAfterDivZeroChecker::checkEndFunction(CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ DivZeroMapTy DivZeroes = State->get<DivZeroMap>();
+ if (DivZeroes.isEmpty())
+ return;
+
+ DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>();
+ for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(),
+ E = DivZeroes.end();
+ I != E; ++I) {
+ ZeroState ZS = *I;
+ if (ZS.getStackFrameContext() == C.getStackFrame())
+ DivZeroes = F.remove(DivZeroes, ZS);
+ }
+ C.addTransition(State->set<DivZeroMap>(DivZeroes));
+}
+
+void TestAfterDivZeroChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
+ BinaryOperator::Opcode Op = B->getOpcode();
+ if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
+ Op == BO_RemAssign) {
+ SVal S = C.getSVal(B->getRHS());
+
+ if (!isZero(S, C))
+ setDivZeroMap(S, C);
+ }
+}
+
+void TestAfterDivZeroChecker::checkBranchCondition(const Stmt *Condition,
+ CheckerContext &C) const {
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) {
+ if (B->isComparisonOp()) {
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS());
+ bool LRHS = true;
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS());
+ LRHS = false;
+ }
+
+ if (!IntLiteral || IntLiteral->getValue() != 0)
+ return;
+
+ SVal Val = C.getSVal(LRHS ? B->getLHS() : B->getRHS());
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ }
+ } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)) {
+ if (U->getOpcode() == UO_LNot) {
+ SVal Val;
+ if (const ImplicitCastExpr *I =
+ dyn_cast<ImplicitCastExpr>(U->getSubExpr()))
+ Val = C.getSVal(I->getSubExpr());
+
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ else {
+ Val = C.getSVal(U->getSubExpr());
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ }
+ }
+ } else if (const ImplicitCastExpr *IE =
+ dyn_cast<ImplicitCastExpr>(Condition)) {
+ SVal Val = C.getSVal(IE->getSubExpr());
+
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ else {
+ SVal Val = C.getSVal(Condition);
+
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ }
+ }
+}
+
+void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) {
+ mgr.registerChecker<TestAfterDivZeroChecker>();
+}
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 38aac28..7944c7e 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -140,8 +140,8 @@
/*Default=*/false);
}
-bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() {
- return getBooleanOption(InlineCXXContainerCtorsAndDtors,
+bool AnalyzerOptions::mayInlineCXXContainerMethods() {
+ return getBooleanOption(InlineCXXContainerMethods,
"c++-container-inlining",
/*Default=*/false);
}
@@ -189,6 +189,13 @@
/* Default = */ false);
}
+
+bool AnalyzerOptions::shouldWriteStableReportFilename() {
+ return getBooleanOption(StableReportFilename,
+ "stable-report-filename",
+ /* Default = */ false);
+}
+
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 6c7cb23..141a48b 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -125,7 +125,7 @@
break;
if (PathDiagnosticEventPiece *nextEvent =
- dyn_cast<PathDiagnosticEventPiece>(path.front().getPtr())) {
+ dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
PathDiagnosticEventPiece *event =
cast<PathDiagnosticEventPiece>(piece);
// Check to see if we should keep one of the two pieces. If we
@@ -1412,7 +1412,7 @@
if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
if (const Expr *Ex = PS->getStmtAs<Expr>())
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
}
@@ -1420,7 +1420,7 @@
const Stmt *S = CE->getCalleeContext()->getCallSite();
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
}
@@ -1491,7 +1491,7 @@
const LocationContext *CalleeCtx = PDB.LC;
if (CallerCtx != CalleeCtx) {
reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(),
+ N->getState().get(),
CalleeCtx, CallerCtx);
}
}
@@ -1674,7 +1674,7 @@
PathDiagnosticCallPiece *C;
if (VisitedEntireCall) {
- PathDiagnosticPiece *P = PD.getActivePath().front().getPtr();
+ PathDiagnosticPiece *P = PD.getActivePath().front().get();
C = cast<PathDiagnosticCallPiece>(P);
} else {
const Decl *Caller = CE->getLocationContext()->getDecl();
@@ -1728,7 +1728,7 @@
// Propagate the interesting symbols accordingly.
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
}
@@ -1756,7 +1756,7 @@
// interesting symbols correctly.
if (const Expr *Ex = PS->getStmtAs<Expr>())
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
// Add an edge. If this is an ObjCForCollectionStmt do
@@ -1779,7 +1779,7 @@
const LocationContext *CalleeCtx = PDB.LC;
if (CallerCtx != CalleeCtx) {
reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(),
+ N->getState().get(),
CalleeCtx, CallerCtx);
}
}
@@ -2995,7 +2995,7 @@
for (PathPieces::const_iterator I = path.begin(), E = path.end();
I!=E; ++I) {
- PathDiagnosticPiece *piece = I->getPtr();
+ PathDiagnosticPiece *piece = I->get();
// Recursively compact calls.
if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index b415d5b..0503ace 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -724,7 +724,7 @@
bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
if (IsZeroCheck)
return N->getState()->isNull(Constraint).isUnderconstrained();
- return N->getState()->assume(Constraint, !Assumption);
+ return (bool)N->getState()->assume(Constraint, !Assumption);
}
PathDiagnosticPiece *
@@ -1285,13 +1285,13 @@
if (quotes) {
Out << '\'';
const LocationContext *LCtx = N->getLocationContext();
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()),
LCtx).getAsRegion()) {
if (report.isInteresting(R))
prunable = false;
else {
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
SVal V = state->getSVal(R);
if (report.isInteresting(V))
prunable = false;
@@ -1446,7 +1446,7 @@
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
if (report.isInteresting(R))
event->setPrunable(false);
@@ -1490,7 +1490,7 @@
PathDiagnosticEventPiece *event =
new PathDiagnosticEventPiece(Loc, Out.str());
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
if (report.isInteresting(R))
event->setPrunable(false);
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index a02e413..7e0670a 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -311,7 +311,7 @@
ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const {
const FunctionDecl *D = getDecl();
if (!D)
- return llvm::ArrayRef<ParmVarDecl*>();
+ return None;
return D->parameters();
}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index e710c7f..4623c35 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -541,7 +541,7 @@
CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
PostStmt Loc(CS.getStmt(), N->getLocationContext());
- if (Loc == N->getLocation()) {
+ if (Loc == N->getLocation().withTag(nullptr)) {
// Note: 'N' should be a fresh node because otherwise it shouldn't be
// a member of Deferred.
WList->enqueue(N, Block, Idx+1);
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 6a26650..ae5a4cc 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -205,7 +205,8 @@
}
const Stmt *S = En.getStmt();
-
+ assert(S != nullptr && "Expected non-null Stmt");
+
Out << " (" << (const void*) En.getLocationContext() << ','
<< (const void*) S << ") ";
LangOptions LO; // FIXME.
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index ac87d58..9b7e746 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -699,6 +699,7 @@
case Stmt::FunctionParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHLeaveStmtClass:
case Stmt::LambdaExprClass:
case Stmt::SEHFinallyStmtClass: {
const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
@@ -732,6 +733,12 @@
case Stmt::CapturedStmtClass:
case Stmt::OMPParallelDirectiveClass:
case Stmt::OMPSimdDirectiveClass:
+ case Stmt::OMPForDirectiveClass:
+ case Stmt::OMPSectionsDirectiveClass:
+ case Stmt::OMPSectionDirectiveClass:
+ case Stmt::OMPSingleDirectiveClass:
+ case Stmt::OMPParallelForDirectiveClass:
+ case Stmt::OMPParallelSectionsDirectiveClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
case Stmt::ObjCSubscriptRefExprClass:
@@ -2252,9 +2259,8 @@
ProgramStateRef state = Pred->getState();
- for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(),
- OE = A->end_outputs(); OI != OE; ++OI) {
- SVal X = state->getSVal(*OI, Pred->getLocationContext());
+ for (const Expr *O : A->outputs()) {
+ SVal X = state->getSVal(O, Pred->getLocationContext());
assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef.
if (Optional<Loc> LV = X.getAs<Loc>())
@@ -2428,7 +2434,8 @@
if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
LangOptions LO; // FIXME.
- C->getLHS()->printPretty(Out, nullptr, PrintingPolicy(LO));
+ if (C->getLHS())
+ C->getLHS()->printPretty(Out, nullptr, PrintingPolicy(LO));
if (const Stmt *RHS = C->getRHS()) {
Out << " .. ";
@@ -2471,6 +2478,7 @@
default: {
const Stmt *S = Loc.castAs<StmtPoint>().getStmt();
+ assert(S != nullptr && "Expecting non-null Stmt");
Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
LangOptions LO; // FIXME.
@@ -2512,7 +2520,7 @@
}
ProgramStateRef state = N->getState();
- Out << "\\|StateID: " << (const void*) state.getPtr()
+ Out << "\\|StateID: " << (const void*) state.get()
<< " NodeID: " << (const void*) N << "\\|";
state->printDOT(Out);
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 4619f62..3f608ba 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -708,18 +708,16 @@
hasMember(Ctx, RD, "iterator_category");
}
-/// Returns true if the given function refers to a constructor or destructor of
-/// a C++ container or iterator.
+/// Returns true if the given function refers to a method of a C++ container
+/// or iterator.
///
-/// We generally do a poor job modeling most containers right now, and would
-/// prefer not to inline their setup and teardown.
-static bool isContainerCtorOrDtor(const ASTContext &Ctx,
- const FunctionDecl *FD) {
- if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)))
- return false;
-
- const CXXRecordDecl *RD = cast<CXXMethodDecl>(FD)->getParent();
- return isContainerClass(Ctx, RD);
+/// We generally do a poor job modeling most containers right now, and might
+/// prefer not to inline their methods.
+static bool isContainerMethod(const ASTContext &Ctx,
+ const FunctionDecl *FD) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ return isContainerClass(Ctx, MD->getParent());
+ return false;
}
/// Returns true if the given function is the destructor of a class named
@@ -765,9 +763,9 @@
// Conditionally control the inlining of methods on objects that look
// like C++ containers.
- if (!Opts.mayInlineCXXContainerCtorsAndDtors())
+ if (!Opts.mayInlineCXXContainerMethods())
if (!Ctx.getSourceManager().isInMainFile(FD->getLocation()))
- if (isContainerCtorOrDtor(Ctx, FD))
+ if (isContainerMethod(Ctx, FD))
return false;
// Conditionally control the inlining of the destructor of C++ shared_ptr.
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index e8ec005..b1e9f06 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -20,11 +20,13 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include <sstream>
using namespace clang;
using namespace ento;
@@ -39,8 +41,9 @@
std::string Directory;
bool createdDir, noDir;
const Preprocessor &PP;
+ AnalyzerOptions &AnalyzerOpts;
public:
- HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
+ HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp);
virtual ~HTMLDiagnostics() { FlushDiagnostics(nullptr); }
@@ -68,16 +71,17 @@
} // end anonymous namespace
-HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
+HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts,
+ const std::string& prefix,
const Preprocessor &pp)
- : Directory(prefix), createdDir(false), noDir(false), PP(pp) {
+ : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) {
}
void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
PathDiagnosticConsumers &C,
const std::string& prefix,
const Preprocessor &PP) {
- C.push_back(new HTMLDiagnostics(prefix, PP));
+ C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP));
}
//===----------------------------------------------------------------------===//
@@ -95,11 +99,11 @@
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
FilesMade *filesMade) {
-
+
// Create the HTML directory if it is missing.
if (!createdDir) {
createdDir = true;
- if (llvm::error_code ec = llvm::sys::fs::create_directories(Directory)) {
+ if (std::error_code ec = llvm::sys::fs::create_directories(Directory)) {
llvm::errs() << "warning: could not create directory '"
<< Directory << "': " << ec.message() << '\n';
@@ -126,11 +130,30 @@
// Create a new rewriter to generate HTML.
Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());
+ // Get the function/method name
+ SmallString<128> declName("unknown");
+ int offsetDecl = 0;
+ if (const Decl *DeclWithIssue = D.getDeclWithIssue()) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
+ declName = ND->getDeclName().getAsString();
+ }
+
+ if (const Stmt *Body = DeclWithIssue->getBody()) {
+ // Retrieve the relative position of the declaration which will be used
+ // for the file name
+ FullSourceLoc L(
+ SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()),
+ SMgr);
+ FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr);
+ offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber();
+ }
+ }
+
// Process the path.
unsigned n = path.size();
unsigned max = n;
- for (PathPieces::const_reverse_iterator I = path.rbegin(),
+ for (PathPieces::const_reverse_iterator I = path.rbegin(),
E = path.rend();
I != E; ++I, --n)
HandlePiece(R, FID, **I, n, max);
@@ -163,6 +186,9 @@
DirName += '/';
}
+ int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber();
+ int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber();
+
// Add the name of the file as an <h1> tag.
{
@@ -176,9 +202,9 @@
<< html::EscapeText(Entry->getName())
<< "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
"<a href=\"#EndPath\">line "
- << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber()
+ << LineNumber
<< ", column "
- << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber()
+ << ColumnNumber
<< "</a></td></tr>\n"
"<tr><td class=\"rowname\">Description:</td><td>"
<< D.getVerboseDescription() << "</td></tr>\n";
@@ -215,12 +241,16 @@
os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
+ os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n";
+
+ os << "\n<!-- FUNCTIONNAME " << declName << " -->\n";
+
os << "\n<!-- BUGLINE "
- << path.back()->getLocation().asLocation().getExpansionLineNumber()
+ << LineNumber
<< " -->\n";
os << "\n<!-- BUGCOLUMN "
- << path.back()->getLocation().asLocation().getExpansionColumnNumber()
+ << ColumnNumber
<< " -->\n";
os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";
@@ -247,13 +277,42 @@
// Create a path for the target HTML file.
int FD;
SmallString<128> Model, ResultPath;
- llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
- if (llvm::error_code EC =
+ if (!AnalyzerOpts.shouldWriteStableReportFilename()) {
+ llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
+
+ if (std::error_code EC =
llvm::sys::fs::createUniqueFile(Model.str(), FD, ResultPath)) {
- llvm::errs() << "warning: could not create file in '" << Directory
- << "': " << EC.message() << '\n';
- return;
+ llvm::errs() << "warning: could not create file in '" << Directory
+ << "': " << EC.message() << '\n';
+ return;
+ }
+
+ } else {
+ int i = 1;
+ std::error_code EC;
+ do {
+ // Find a filename which is not already used
+ std::stringstream filename;
+ Model = "";
+ filename << "report-"
+ << llvm::sys::path::filename(Entry->getName()).str()
+ << "-" << declName.c_str()
+ << "-" << offsetDecl
+ << "-" << i << ".html";
+ llvm::sys::path::append(Model, Directory,
+ filename.str());
+ EC = llvm::sys::fs::openFileForWrite(Model.str(),
+ FD,
+ llvm::sys::fs::F_RW |
+ llvm::sys::fs::F_Excl);
+ if (EC && EC != std::errc::file_exists) {
+ llvm::errs() << "warning: could not create file '" << Model.str()
+ << "': " << EC.message() << '\n';
+ return;
+ }
+ i++;
+ } while (EC);
}
llvm::raw_fd_ostream os(FD, true);
@@ -458,7 +517,7 @@
<< (num + 1)
<< ")\">→</a></div></td>";
}
-
+
os << "</tr></table>";
}
}
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 12bbfdf..22711f5 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -508,10 +508,12 @@
}
void StringRegion::dumpToStream(raw_ostream &os) const {
+ assert(Str != nullptr && "Expecting non-null StringLiteral");
Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
}
void ObjCStringRegion::dumpToStream(raw_ostream &os) const {
+ assert(Str != nullptr && "Expecting non-null ObjCStringLiteral");
Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index a9527de..fd25bd8 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -67,7 +67,7 @@
void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
bool ShouldFlattenMacros) const {
for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
- PathDiagnosticPiece *Piece = I->getPtr();
+ PathDiagnosticPiece *Piece = I->get();
switch (Piece->getKind()) {
case PathDiagnosticPiece::Call: {
@@ -157,7 +157,7 @@
if (path.empty())
return;
- PathDiagnosticPiece *LastP = path.back().getPtr();
+ PathDiagnosticPiece *LastP = path.back().get();
assert(LastP);
const SourceManager &SMgr = LastP->getLocation().getManager();
@@ -222,7 +222,7 @@
for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
++I) {
- const PathDiagnosticPiece *piece = I->getPtr();
+ const PathDiagnosticPiece *piece = I->get();
FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
if (FID.isInvalid()) {
@@ -1037,7 +1037,7 @@
static void compute_path_size(const PathPieces &pieces, unsigned &size) {
for (PathPieces::const_iterator it = pieces.begin(),
et = pieces.end(); it != et; ++it) {
- const PathDiagnosticPiece *piece = it->getPtr();
+ const PathDiagnosticPiece *piece = it->get();
if (const PathDiagnosticCallPiece *cp =
dyn_cast<PathDiagnosticCallPiece>(piece)) {
compute_path_size(cp->path, size);
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 2585e54..ba3ad2e 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -173,8 +173,8 @@
}
// Output the call depth.
- Indent(o, indent) << "<key>depth</key>"
- << "<integer>" << depth << "</integer>\n";
+ Indent(o, indent) << "<key>depth</key>";
+ EmitInteger(o, depth) << '\n';
// Output the text.
assert(!P.getString().empty());
@@ -311,7 +311,7 @@
for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
++I) {
- const PathDiagnosticPiece *piece = I->getPtr();
+ const PathDiagnosticPiece *piece = I->get();
AddFID(FM, Fids, *SM, piece->getLocation().asLocation());
ArrayRef<SourceRange> Ranges = piece->getRanges();
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
@@ -345,8 +345,7 @@
return;
}
- // Write the plist header.
- o << PlistHeader;
+ EmitPlistHeader(o);
// Write the root object: a <dict> containing...
// - "clang_version", the string representation of clang version
@@ -358,11 +357,8 @@
o << " <key>files</key>\n"
" <array>\n";
- for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
- I!=E; ++I) {
- o << " ";
- EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n';
- }
+ for (FileID FID : Fids)
+ EmitString(o << " ", SM->getFileEntryForID(FID)->getName()) << '\n';
o << " </array>\n"
" <key>diagnostics</key>\n"
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index ccaa8b6..12e514b 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -214,7 +214,7 @@
default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
case PD_##NAME: \
- CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP); \
+ CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \
break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
}