summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorDevin Coughlin <dcoughlin@apple.com>2015-09-16 22:03:05 +0000
committerDevin Coughlin <dcoughlin@apple.com>2015-09-16 22:03:05 +0000
commite39bd407ba29cf8ba20ec4f02f6a84b17cee2cb3 (patch)
tree5f8bd741b566a35aa94d9bd2083dea47af1619ea /clang/lib/StaticAnalyzer
parenteade07ba59210f8fde8679d56ce37d58f1112691 (diff)
downloadbcm5719-llvm-e39bd407ba29cf8ba20ec4f02f6a84b17cee2cb3.tar.gz
bcm5719-llvm-e39bd407ba29cf8ba20ec4f02f6a84b17cee2cb3.zip
[analyzer] Add generateErrorNode() APIs to CheckerContext.
The analyzer trims unnecessary nodes from the exploded graph before reporting path diagnostics. However, in some cases it can trim all nodes (including the error node), leading to an assertion failure (see https://llvm.org/bugs/show_bug.cgi?id=24184). This commit addresses the issue by adding two new APIs to CheckerContext to explicitly create error nodes. Unless the client provides a custom tag, these APIs tag the node with the checker's tag -- preventing it from being trimmed. The generateErrorNode() method creates a sink error node, while generateNonFatalErrorNode() creates an error node for a path that should continue being explored. The intent is that one of these two methods should be used whenever a checker creates an error node. This commit updates the checkers to use these APIs. These APIs (unlike addTransition() and generateSink()) do not take an explicit Pred node. This is because there are not any error nodes in the checkers that were created with an explicit different than the default (the CheckerContext's Pred node). It also changes generateSink() to require state and pred nodes (previously these were optional) to reduce confusion. Additionally, there were several cases where checkers did check whether a generated node could be null; we now explicitly check for null in these places. This commit also includes a test case written by Ying Yi as part of http://reviews.llvm.org/D12163 (that patch originally addressed this issue but was reverted because it introduced false positive regressions). Differential Revision: http://reviews.llvm.org/D12780 llvm-svn: 247859
Diffstat (limited to 'clang/lib/StaticAnalyzer')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp16
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp16
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp24
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporter.cpp5
43 files changed, 126 insertions, 102 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 45706c2f2f6..c092610afe2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -62,7 +62,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
- ExplodedNode *N = C.generateSink(StOutBound);
+ ExplodedNode *N = C.generateErrorNode(StOutBound);
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index bc790d4584f..f4de733bd79 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -182,7 +182,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
ProgramStateRef errorState,
OOB_Kind kind) const {
- ExplodedNode *errorNode = checkerContext.generateSink(errorState);
+ ExplodedNode *errorNode = checkerContext.generateErrorNode(errorState);
if (!errorNode)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 6adf39f3755..e157478433c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -140,7 +140,7 @@ void NilArgChecker::warnIfNilExpr(const Expr *E,
ProgramStateRef State = C.getState();
if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
generateBugReport(N, Msg, E->getSourceRange(), E, C);
}
@@ -157,7 +157,7 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C,
if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
@@ -489,14 +489,15 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
if (SourceSize == TargetSize)
return;
- // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
- // otherwise generate a regular node.
+ // Generate an error. Only generate a sink error node
+ // if 'SourceSize < TargetSize'; otherwise generate a non-fatal error node.
//
// FIXME: We can actually create an abstract "CFNumber" object that has
// the bits initialized to the provided values.
//
- if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
- : C.addTransition()) {
+ ExplodedNode *N = SourceSize < TargetSize ? C.generateErrorNode()
+ : C.generateNonFatalErrorNode();
+ if (N) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
@@ -589,7 +590,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
if (stateTrue && !stateFalse) {
- ExplodedNode *N = C.generateSink(stateTrue);
+ ExplodedNode *N = C.generateErrorNode(stateTrue);
if (!N)
return;
@@ -656,7 +657,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
@@ -800,7 +801,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// Generate only one error node to use for all bug reports.
if (!errorNode.hasValue())
- errorNode = C.addTransition();
+ errorNode = C.generateNonFatalErrorNode();
if (!errorNode.getValue())
continue;
@@ -1025,7 +1026,7 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
}
if (!State)
- C.generateSink();
+ C.generateSink(C.getState(), C.getPredecessor());
else if (State != C.getState())
C.addTransition(State);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index b4ac316fdce..f26f73129e7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -32,7 +32,7 @@ namespace {
void BoolAssignmentChecker::emitReport(ProgramStateRef state,
CheckerContext &C) const {
- if (ExplodedNode *N = C.addTransition(state)) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT)
BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N));
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 477bea74d8c..07c341400e7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -229,7 +229,7 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
if (!Filter.CheckCStringNullArg)
return nullptr;
- ExplodedNode *N = C.generateSink(stateNull);
+ ExplodedNode *N = C.generateErrorNode(stateNull);
if (!N)
return nullptr;
@@ -292,7 +292,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true);
ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false);
if (StOutBound && !StInBound) {
- ExplodedNode *N = C.generateSink(StOutBound);
+ ExplodedNode *N = C.generateErrorNode(StOutBound);
if (!N)
return nullptr;
@@ -525,7 +525,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
const Stmt *First, const Stmt *Second) const {
- ExplodedNode *N = C.generateSink(state);
+ ExplodedNode *N = C.generateErrorNode(state);
if (!N)
return;
@@ -585,7 +585,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
if (stateOverflow && !stateOkay) {
// We have an overflow. Emit a bug report.
- ExplodedNode *N = C.generateSink(stateOverflow);
+ ExplodedNode *N = C.generateErrorNode(stateOverflow);
if (!N)
return nullptr;
@@ -706,7 +706,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
if (!Filter.CheckCStringNotNullTerm)
return UndefinedVal();
- if (ExplodedNode *N = C.addTransition(state)) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT_NotCString)
BT_NotCString.reset(new BuiltinBug(
Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
@@ -766,7 +766,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
if (!Filter.CheckCStringNotNullTerm)
return UndefinedVal();
- if (ExplodedNode *N = C.addTransition(state)) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT_NotCString)
BT_NotCString.reset(new BuiltinBug(
Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 33a24d816c5..750cbda4597 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -97,7 +97,7 @@ private:
void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
const Expr *BadE) {
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
@@ -169,7 +169,7 @@ bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
const ProgramStateRef State = C.getState();
const SVal PSV = State->getSVal(SValMemRegion);
if (PSV.isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
auto R = llvm::make_unique<BugReport>(*BT, Message, N);
R->addRange(ArgRange);
@@ -200,7 +200,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
return true;
if (V.isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
// Generate a report for this bug.
@@ -265,7 +265,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
D->getStore());
if (F.Find(D->getRegion())) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
SmallString<512> Str;
llvm::raw_svector_ostream os(Str);
@@ -338,7 +338,7 @@ void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
SVal Arg = C.getSVal(DE->getArgument());
if (Arg.isUndef()) {
StringRef Desc;
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
if (!BT_cxx_delete_undef)
@@ -395,7 +395,7 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
// the function.
unsigned Params = FD->getNumParams();
if (Call.getNumArgs() < Params) {
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
@@ -443,7 +443,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
SVal recVal = msg.getReceiverSVal();
if (recVal.isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
BugType *BT = nullptr;
switch (msg.getMessageKind()) {
case OCM_Message:
@@ -559,7 +559,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
Ctx.LongDoubleTy == CanRetTy ||
Ctx.LongLongTy == CanRetTy ||
Ctx.UnsignedLongLongTy == CanRetTy)))) {
- if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
+ if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
emitNilReceiverBug(C, Msg, N);
return;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 0d683f96df0..a5ed64d160a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -131,7 +131,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy))
return;
- if (ExplodedNode *errorNode = C.generateSink()) {
+ if (ExplodedNode *errorNode = C.generateErrorNode()) {
if (!BT)
BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
"Cast a region whose size is not a multiple"
diff --git a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index ba3024d78a1..fa7841356ef 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -56,7 +56,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE,
// Now the cast-to-type is struct pointer, the original type is not void*.
if (!OrigPointeeTy->isRecordType()) {
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT)
BT.reset(
new BuiltinBug(this, "Cast from non-struct type to struct type",
diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index cefdb064534..3ad1996db89 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -140,7 +140,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
if (k)
if (isRootChanged((intptr_t) *k))
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_BreakJail)
BT_BreakJail.reset(new BuiltinBug(
this, "Break out of jail", "No call of chdir(\"/\") immediately "
diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 0df31860906..8d41a25c281 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -91,7 +91,7 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
CheckerContext &C, bool IsBind) const {
// Generate an error node.
- ExplodedNode *N = C.generateSink(State);
+ ExplodedNode *N = C.generateErrorNode(State);
if (!N)
return;
@@ -184,7 +184,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
CheckerContext &C) const {
// Check for dereference of an undefined value.
if (l.isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_undef)
BT_undef.reset(
new BuiltinBug(this, "Dereference of undefined pointer value"));
@@ -219,7 +219,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
// Otherwise, we have the case where the location could either be
// null or not-null. Record the error node as an "implicit" null
// dereference.
- if (ExplodedNode *N = C.generateSink(nullState)) {
+ if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
/*IsDirectDereference=*/false};
dispatchEvent(event);
@@ -257,7 +257,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
// At this point the value could be either null or non-null.
// Record this as an "implicit" null dereference.
- if (ExplodedNode *N = C.generateSink(StNull)) {
+ if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
&C.getBugReporter(),
/*IsDirectDereference=*/false};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 211a1c1d0cf..59850230563 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -35,7 +35,7 @@ public:
void DivZeroChecker::reportBug(const char *Msg,
ProgramStateRef StateZero,
CheckerContext &C) const {
- if (ExplodedNode *N = C.generateSink(StateZero)) {
+ if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
if (!BT)
BT.reset(new BuiltinBug(this, "Division by zero"));
diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 7dc0a874595..60c6aa534d1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -86,8 +86,7 @@ static const char *getArgumentValueString(const CallExpr *CE,
void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
CheckerContext &C) const {
- ExplodedNode *N = C.getPredecessor();
- const LocationContext *LC = N->getLocationContext();
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
// A specific instantiation of an inlined function may have more constrained
// values than can generally be assumed. Skip the check.
@@ -97,24 +96,28 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
if (!BT)
BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ if (!N)
+ return;
C.emitReport(
llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
}
void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
CheckerContext &C) const {
- ExplodedNode *N = C.getPredecessor();
if (!BT)
BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ if (!N)
+ return;
C.emitReport(llvm::make_unique<BugReport>(*BT, "REACHABLE", N));
}
void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
CheckerContext &C) const {
- ExplodedNode *N = C.getPredecessor();
- const LocationContext *LC = N->getLocationContext();
+ const LocationContext *LC = C.getPredecessor()->getLocationContext();
// An inlined function could conceivably also be analyzed as a top-level
// function. We ignore this case and only emit a message (TRUE or FALSE)
@@ -127,6 +130,9 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
if (!BT)
BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ if (!N)
+ return;
C.emitReport(
llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index ae226f727c7..3fe89f96a43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -50,7 +50,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
if (!RV.isConstant() || RV.isZeroConstant())
return;
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT)
BT.reset(
new BuiltinBug(this, "Use fixed address",
diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index cb2bf108ef7..1d8085108c0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -640,7 +640,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
return false;
// Generate diagnostic.
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
initBugType();
auto report = llvm::make_unique<BugReport>(*BT, Msg, N);
report->addRange(E->getSourceRange());
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 932d3d6ffff..547aa7540d9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -255,7 +255,7 @@ void MacOSKeychainAPIChecker::
CheckerContext &C) const {
ProgramStateRef State = C.getState();
State = State->remove<AllocatedData>(AP.first);
- ExplodedNode *N = C.addTransition(State);
+ ExplodedNode *N = C.generateNonFatalErrorNode(State);
if (!N)
return;
@@ -301,7 +301,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// Remove the value from the state. The new symbol will be added for
// tracking when the second allocator is processed in checkPostStmt().
State = State->remove<AllocatedData>(V);
- ExplodedNode *N = C.addTransition(State);
+ ExplodedNode *N = C.generateNonFatalErrorNode(State);
if (!N)
return;
initBugType();
@@ -364,7 +364,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
if (isEnclosingFunctionParam(ArgExpr))
return;
- ExplodedNode *N = C.addTransition(State);
+ ExplodedNode *N = C.generateNonFatalErrorNode(State);
if (!N)
return;
initBugType();
@@ -430,7 +430,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// report a bad call to free.
if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
!definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
- ExplodedNode *N = C.addTransition(State);
+ ExplodedNode *N = C.generateNonFatalErrorNode(State);
if (!N)
return;
initBugType();
@@ -584,7 +584,9 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
}
static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak");
- ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
+ ExplodedNode *N = C.generateNonFatalErrorNode(C.getState(), &Tag);
+ if (!N)
+ return;
// Generate the error reports.
for (const auto P : Errors)
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 4ce936aa0fe..4cbe97b2607 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -62,7 +62,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
- ExplodedNode *N = C.generateSink(state);
+ ExplodedNode *N = C.generateErrorNode(state);
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index c95b2fd7f4b..d5c5cc1dbae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1592,7 +1592,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
if (!CheckKind.hasValue())
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_BadFree[*CheckKind])
BT_BadFree[*CheckKind].reset(
new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
@@ -1637,7 +1637,7 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
else
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_FreeAlloca[*CheckKind])
BT_FreeAlloca[*CheckKind].reset(
new BugType(CheckNames[*CheckKind], "Free alloca()", "Memory Error"));
@@ -1661,7 +1661,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
if (!ChecksEnabled[CK_MismatchedDeallocatorChecker])
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_MismatchedDealloc)
BT_MismatchedDealloc.reset(
new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
@@ -1720,7 +1720,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
if (!CheckKind.hasValue())
return;
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
@@ -1774,7 +1774,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
if (!CheckKind.hasValue())
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_UseFree[*CheckKind])
BT_UseFree[*CheckKind].reset(new BugType(
CheckNames[*CheckKind], "Use-after-free", "Memory Error"));
@@ -1801,7 +1801,7 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
if (!CheckKind.hasValue())
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_DoubleFree[*CheckKind])
BT_DoubleFree[*CheckKind].reset(
new BugType(CheckNames[*CheckKind], "Double free", "Memory Error"));
@@ -1829,7 +1829,7 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
if (!CheckKind.hasValue())
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_DoubleDelete)
BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
"Double delete", "Memory Error"));
@@ -1856,7 +1856,7 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
if (!CheckKind.hasValue())
return;
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_UseZerroAllocated[*CheckKind])
BT_UseZerroAllocated[*CheckKind].reset(new BugType(
CheckNames[*CheckKind], "Use of zero allocated", "Memory Error"));
@@ -2150,10 +2150,12 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ExplodedNode *N = C.getPredecessor();
if (!Errors.empty()) {
static CheckerProgramPointTag Tag("MallocChecker", "DeadSymbolsLeak");
- N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
- for (SmallVectorImpl<SymbolRef>::iterator
+ N = C.generateNonFatalErrorNode(C.getState(), &Tag);
+ if (N) {
+ for (SmallVectorImpl<SymbolRef>::iterator
I = Errors.begin(), E = Errors.end(); I != E; ++I) {
- reportLeak(*I, N, C);
+ reportLeak(*I, N, C);
+ }
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 5d9b32fa911..0e7894788c8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -62,7 +62,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
BT.reset(new BugType(this, "Use -drain instead of -release",
"API Upgrade (Apple)"));
- ExplodedNode *N = C.addTransition();
+ ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N) {
assert(0);
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index ba82d1d1d41..8d0a060fc45 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -81,7 +81,7 @@ void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
}
if (BuildSinks)
- C.generateSink();
+ C.generateSink(C.getState(), C.getPredecessor());
}
void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
@@ -90,7 +90,7 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
if (const ObjCMethodDecl *MD = Msg.getDecl()) {
MD = MD->getCanonicalDecl();
if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
- C.generateSink();
+ C.generateSink(C.getState(), C.getPredecessor());
return;
}
}
@@ -136,7 +136,7 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
}
// If we got here, it's one of the messages we care about.
- C.generateSink();
+ C.generateSink(C.getState(), C.getPredecessor());
}
void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index a7586c412af..1f82ab94af8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -143,7 +143,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
if (!stateNotNull) {
// Generate an error node. Check for a null node in case
// we cache out.
- if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
+ if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
std::unique_ptr<BugReport> R;
if (haveAttrNonNull)
@@ -161,7 +161,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
// Always return. Either we cached out or we just emitted an error.
return;
}
- if (ExplodedNode *N = C.generateSink(stateNull)) {
+ if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
ImplicitNullDerefEvent event = {
V, false, N, &C.getBugReporter(),
/*IsDirectDereference=*/haveRefTypeParam};
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 74a7e38e944..137dedbf4ce 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -499,7 +499,9 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
Nullness == NullConstraint::IsNull &&
StaticNullability == Nullability::Nonnull) {
static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
- ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag);
+ ExplodedNode *N = C.generateErrorNode(State, &Tag);
+ if (!N)
+ return;
reportBugIfPreconditionHolds(ErrorKind::NilReturnedToNonnull, N, nullptr, C,
RetExpr);
return;
@@ -569,7 +571,9 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call,
if (Filter.CheckNullPassedToNonnull && Nullness == NullConstraint::IsNull &&
ArgStaticNullability != Nullability::Nonnull &&
ParamNullability == Nullability::Nonnull) {
- ExplodedNode *N = C.generateSink(State);
+ ExplodedNode *N = C.generateErrorNode(State);
+ if (!N)
+ return;
reportBugIfPreconditionHolds(ErrorKind::NilPassedToNonnull, N, nullptr, C,
ArgExpr);
return;
@@ -891,7 +895,9 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S,
ValNullability != Nullability::Nonnull &&
LocNullability == Nullability::Nonnull) {
static CheckerProgramPointTag Tag(this, "NullPassedToNonnull");
- ExplodedNode *N = C.generateSink(State, C.getPredecessor(), &Tag);
+ ExplodedNode *N = C.generateErrorNode(State, &Tag);
+ if (!N)
+ return;
reportBugIfPreconditionHolds(ErrorKind::NilAssignedToNonnull, N, nullptr, C,
S);
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index a7b92b4c67f..cbaa5c23592 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -43,7 +43,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// Uninitialized value used for the mutex?
if (V.getAs<UndefinedVal>()) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_undef)
BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex "
"for @synchronized"));
@@ -66,7 +66,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
if (!notNullState) {
// Generate an error node. This isn't a sink since
// a null mutex just means no synchronization occurs.
- if (ExplodedNode *N = C.addTransition(nullState)) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) {
if (!BT_null)
BT_null.reset(new BuiltinBug(
this, "Nil value used as mutex for @synchronized() "
diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index 14f4969c444..0203d79cd00 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -139,7 +139,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
ProgramStateRef StInBound = State->assumeInBound(Idx, *Size, true, T);
ProgramStateRef StOutBound = State->assumeInBound(Idx, *Size, false, T);
if (StOutBound && !StInBound) {
- ExplodedNode *N = C.generateSink(StOutBound);
+ ExplodedNode *N = C.generateErrorNode(StOutBound);
if (!N)
return;
initBugType();
diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 193f515d1ca..f344dd09c7a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -153,7 +153,7 @@ void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
return;
// Generate an error node.
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 313fe7c43e0..e3369677af7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -51,7 +51,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
isa<CompoundLiteralRegion>(LR)) {
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT)
BT.reset(
new BuiltinBug(this, "Dangerous pointer arithmetic",
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index a3b02d99741..2d33ebc2610 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -60,7 +60,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
return;
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT)
BT.reset(
new BuiltinBug(this, "Pointer subtraction",
diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 4b8c0b7a98e..426c97dbd4c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -142,7 +142,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
if (!BT_doublelock)
BT_doublelock.reset(new BugType(this, "Double locking",
"Lock checker"));
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
auto report = llvm::make_unique<BugReport>(
@@ -204,7 +204,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
if (!BT_doubleunlock)
BT_doubleunlock.reset(new BugType(this, "Double unlocking",
"Lock checker"));
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
auto Report = llvm::make_unique<BugReport>(
@@ -227,7 +227,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
if (firstLockR != lockR) {
if (!BT_lor)
BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker"));
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
auto report = llvm::make_unique<BugReport>(
@@ -272,7 +272,7 @@ void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
if (!BT_destroylock)
BT_destroylock.reset(new BugType(this, "Destroy invalid lock",
"Lock checker"));
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
auto Report = llvm::make_unique<BugReport>(*BT_destroylock, Message, N);
@@ -307,7 +307,7 @@ void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
if (!BT_initlock)
BT_initlock.reset(new BugType(this, "Init invalid lock",
"Lock checker"));
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
auto Report = llvm::make_unique<BugReport>(*BT_initlock, Message, N);
@@ -320,7 +320,7 @@ void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
if (!BT_destroylock)
BT_destroylock.reset(new BugType(this, "Use destroyed lock",
"Lock checker"));
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
auto Report = llvm::make_unique<BugReport>(
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 490a242191b..0610beb7bf3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -3306,7 +3306,7 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
return;
- ExplodedNode *N = C.generateSink(St);
+ ExplodedNode *N = C.generateErrorNode(St);
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index d94299c050d..19fa0fb193c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -62,7 +62,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
if (StOutBound && !StInBound) {
- ExplodedNode *N = C.generateSink(StOutBound);
+ ExplodedNode *N = C.generateErrorNode(StOutBound);
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 2668ac1e1ec..c5e826a84b8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -80,7 +80,7 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
const Expr *TrackingE = nullptr) {
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index e1b2eaf46d8..7026a2ec16a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -200,7 +200,9 @@ void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
State = State->remove<StreamMap>(Sym);
}
- ExplodedNode *N = C.addTransition(State);
+ ExplodedNode *N = C.generateNonFatalErrorNode(State);
+ if (!N)
+ return;
reportLeaks(LeakedStreams, C, N);
}
@@ -208,7 +210,7 @@ void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym,
const CallEvent &Call,
CheckerContext &C) const {
// We reached a bug, stop exploring the path here by generating a sink.
- ExplodedNode *ErrNode = C.generateSink();
+ ExplodedNode *ErrNode = C.generateErrorNode();
// If we've already reached this node on another path, return.
if (!ErrNode)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index f57cd70fd44..2eefb93e23a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -94,7 +94,7 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
const Expr *RetE) const {
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
@@ -211,7 +211,7 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
return;
// Generate an error node.
- ExplodedNode *N = Ctx.addTransition(state);
+ ExplodedNode *N = Ctx.generateNonFatalErrorNode(state);
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index f9dfd38e1f8..82b01fe814d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -271,7 +271,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
if (x >= 0 && x <= 2)
return;
- if (ExplodedNode *N = C.addTransition(state)) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT_illegalwhence)
BT_illegalwhence.reset(
new BuiltinBug(this, "Illegal whence argument",
@@ -349,7 +349,7 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
if (!stateNotNull && stateNull) {
- if (ExplodedNode *N = C.generateSink(stateNull)) {
+ if (ExplodedNode *N = C.generateErrorNode(stateNull)) {
if (!BT_nullfp)
BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer",
"Stream pointer might be NULL."));
@@ -378,7 +378,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
// Check: Double close a File Descriptor could cause undefined behaviour.
// Conforming to man-pages
if (SS->isClosed()) {
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (N) {
if (!BT_doubleclose)
BT_doubleclose.reset(new BuiltinBug(
@@ -406,7 +406,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
continue;
if (SS->isOpened()) {
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (N) {
if (!BT_ResourceLeak)
BT_ResourceLeak.reset(new BuiltinBug(
diff --git a/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
index 6e2477579f5..2e0529015ca 100644
--- a/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -48,7 +48,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E,
return;
if (State->isTainted(E, C.getLocationContext())) {
- if (ExplodedNode *N = C.addTransition()) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
initBugType();
auto report = llvm::make_unique<BugReport>(*BT, "tainted",N);
report->addRange(E->getSourceRange());
diff --git a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
index 638701da8a0..b794d2f86bb 100644
--- a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -167,7 +167,7 @@ bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
}
void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
- if (ExplodedNode *N = C.generateSink(C.getState())) {
+ if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
if (!DivZeroBug)
DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 268e957ea5b..ed17610e411 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -62,7 +62,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
if (X.isUndef()) {
// Generate a sink node, which implicitly marks both outgoing branches as
// infeasible.
- ExplodedNode *N = Ctx.generateSink();
+ ExplodedNode *N = Ctx.generateErrorNode();
if (N) {
if (!BT)
BT.reset(new BuiltinBug(
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 0f426b5d54e..17fe8610da0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -74,7 +74,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
// Get the VarRegion associated with VD in the local stack frame.
if (Optional<UndefinedVal> V =
state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
- if (ExplodedNode *N = C.generateSink()) {
+ if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT)
BT.reset(
new BuiltinBug(this, "uninitialized variable captured by block"));
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 8ae8694ca70..38d2aa6d8f9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -50,7 +50,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
return;
// Generate an error node.
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index c80732f2741..fe07eafd281 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -46,7 +46,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
if (Ctor->isDefaulted())
return;
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
if (!BT)
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 81c96c4860b..7a31efc8cef 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -46,7 +46,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
return;
- ExplodedNode *N = C.generateSink();
+ ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index cf580ad4654..4b78c205834 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -77,7 +77,7 @@ void UnixAPIChecker::ReportOpenBug(CheckerContext &C,
ProgramStateRef State,
const char *Msg,
SourceRange SR) const {
- ExplodedNode *N = C.generateSink(State);
+ ExplodedNode *N = C.generateErrorNode(State);
if (!N)
return;
@@ -182,7 +182,7 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
return;
- ExplodedNode *N = C.generateSink(state);
+ ExplodedNode *N = C.generateErrorNode(state);
if (!N)
return;
@@ -231,7 +231,7 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
ProgramStateRef falseState,
const Expr *arg,
const char *fn_name) const {
- ExplodedNode *N = C.generateSink(falseState);
+ ExplodedNode *N = C.generateErrorNode(falseState);
if (!N)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 8cd3aac7476..e3b2ed22236 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -46,7 +46,7 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind,
ProgramStateRef State,
CheckerContext &C) const {
// Generate an error node.
- ExplodedNode *N = C.generateSink(State);
+ ExplodedNode *N = C.generateErrorNode(State);
if (!N)
return;
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index a3abb1887ef..f70a7d04ae9 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -3224,6 +3224,11 @@ void BugReporter::Register(BugType *BT) {
void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
if (const ExplodedNode *E = R->getErrorNode()) {
+ // An error node must either be a sink or have a tag, otherwise
+ // it could get reclaimed before the path diagnostic is created.
+ assert((E->isSink() || E->getLocation().getTag()) &&
+ "Error node must either be a sink or have a tag");
+
const AnalysisDeclContext *DeclCtx =
E->getLocationContext()->getAnalysisDeclContext();
// The source of autosynthesized body can be handcrafted AST or a model
OpenPOWER on IntegriCloud