From: Ted Kremenek Date: Fri, 9 Mar 2012 01:13:14 +0000 (+0000) Subject: [analyzer] Implement basic path diagnostic pruning based on "interesting" symbols... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=76aadc346c3a4c363238a1e1232f324c3355d9e0;p=clang [analyzer] Implement basic path diagnostic pruning based on "interesting" symbols and regions. Essentially, a bug centers around a story for various symbols and regions. We should only include the path diagnostic events that relate to those symbols and regions. The pruning is done by associating a set of interesting symbols and regions with a BugReporter, which can be modified at BugReport creation or by BugReporterVisitors. This patch reduces the diagnostics emitted in several of our test cases. I've vetted these as having desired behavior. The only regression is a missing null check diagnostic for the return value of realloc() in test/Analysis/malloc-plist.c. This will require some investigation to fix, and I have added a FIXME to the test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152361 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 0978d86de4..b607fe8b2f 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -23,6 +23,7 @@ #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/ImmutableSet.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/DenseSet.h" #include namespace clang { @@ -50,7 +51,7 @@ class BugType; /// This class provides an interface through which checkers can create /// individual bug reports. class BugReport { -public: +public: class NodeResolver { virtual void anchor(); public: @@ -75,6 +76,19 @@ protected: const ExplodedNode *ErrorNode; SmallVector Ranges; ExtraTextList ExtraText; + + typedef llvm::DenseSet Symbols; + typedef llvm::DenseSet Regions; + + /// A set of symbols that are registered with this report as being + /// "interesting", and thus used to help decide which diagnostics + /// to include when constructing the final path diagnostic. + Symbols interestingSymbols; + + /// A set of regions that are registered with this report as being + /// "interesting", and thus used to help decide which diagnostics + /// to include when constructing the final path diagnostic. + Regions interestingRegions; // Not the most efficient data structure, but we use an ImmutableList for the // Callbacks because it is safe to make additions to list during iteration. @@ -121,6 +135,14 @@ public: return ShortDescription.empty() ? Description : ShortDescription; } + void markInteresting(SymbolRef sym); + void markInteresting(const MemRegion *R); + void markInteresting(SVal V); + + bool isInteresting(SymbolRef sym) const; + bool isInteresting(const MemRegion *R) const; + bool isInteresting(SVal V) const; + /// \brief This allows for addition of meta data to the diagnostic. /// /// Currently, only the HTMLDiagnosticClient knows how to display it. @@ -351,7 +373,6 @@ private: // FIXME: Get rid of GRBugReporter. It's the wrong abstraction. class GRBugReporter : public BugReporter { ExprEngine& Eng; - llvm::SmallSet NotableSymbols; public: GRBugReporter(BugReporterData& d, ExprEngine& eng) : BugReporter(d, GRBugReporterKind), Eng(eng) {} @@ -373,14 +394,6 @@ public: virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, SmallVectorImpl &bugReports); - void addNotableSymbol(SymbolRef Sym) { - NotableSymbols.insert(Sym); - } - - bool isNotable(SymbolRef Sym) const { - return (bool) NotableSymbols.count(Sym); - } - /// classof - Used by isa<>, cast<>, and dyn_cast<>. static bool classof(const BugReporter* R) { return R->getKind() == GRBugReporterKind; @@ -399,16 +412,6 @@ public: ExplodedGraph &getGraph() { return BR.getGraph(); } - void addNotableSymbol(SymbolRef Sym) { - // FIXME: For now forward to GRBugReporter. - BR.addNotableSymbol(Sym); - } - - bool isNotable(SymbolRef Sym) const { - // FIXME: For now forward to GRBugReporter. - return BR.isNotable(Sym); - } - ProgramStateManager& getStateManager() { return BR.getStateManager(); } diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h index 5434257dd4..2357cbd095 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -147,40 +147,49 @@ public: const ExplodedNode *N, const CFGBlock *srcBlk, const CFGBlock *dstBlk, + BugReport &R, BugReporterContext &BRC); PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC); + BugReport &R, + const ExplodedNode *N); PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC); + BugReport &R, + const ExplodedNode *N); PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, const bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC); + BugReport &R, + const ExplodedNode *N); PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, const bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC); + BugReport &R, + const ExplodedNode *N); bool patternMatch(const Expr *Ex, llvm::raw_ostream &Out, - BugReporterContext &BRC); + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N, + llvm::Optional &prunable); }; namespace bugreporter { BugReporterVisitor *getTrackNullOrUndefValueVisitor(const ExplodedNode *N, - const Stmt *S); + const Stmt *S, + BugReport *R); const Stmt *GetDerefExpr(const ExplodedNode *N); const Stmt *GetDenomExpr(const ExplodedNode *N); diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 245d5be93e..e98d82bf22 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -19,6 +19,7 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/Optional.h" #include #include #include @@ -357,17 +358,27 @@ public: }; class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { - bool IsPrunable; + llvm::Optional IsPrunable; public: PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, StringRef s, bool addPosRange = true) - : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), - IsPrunable(false) {} + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {} ~PathDiagnosticEventPiece(); - void setPrunable(bool isPrunable) { IsPrunable = isPrunable; } - bool isPrunable() const { return IsPrunable; } + /// Mark the diagnostic piece as being potentially prunable. This + /// flag may have been previously set, at which point it will not + /// be reset unless one specifies to do so. + void setPrunable(bool isPrunable, bool override = false) { + if (IsPrunable.hasValue() && !override) + return; + IsPrunable = isPrunable; + } + + /// Return true if the diagnostic piece is prunable. + bool isPrunable() const { + return IsPrunable.hasValue() ? IsPrunable.getValue() : false; + } static inline bool classof(const PathDiagnosticPiece *P) { return P->getKind() == Event; diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp index 0b11a459ce..ab66e9864f 100644 --- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp @@ -109,7 +109,7 @@ void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, const Expr *arg = *I; R->addRange(arg->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(errorNode, - arg)); + arg, R)); // Emit the bug report. C.EmitReport(R); } diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 1af43d1a33..dd4235af5e 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -411,7 +411,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, BugReport *report = new BugReport(*BT, description, N); report->addRange(Arg->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Arg, + report)); C.EmitReport(report); return; } diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 802103e396..639dd72e9d 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -252,7 +252,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(S->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, S, + report)); C.EmitReport(report); return NULL; } diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index de48769d78..f6014317c8 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -72,7 +72,7 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, BugReport *R = new BugReport(*BT, BT->getName(), N); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetCalleeExpr(N))); + bugreporter::GetCalleeExpr(N), R)); C.EmitReport(R); } @@ -111,7 +111,8 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(argRange); if (argEx) - R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx)); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx, + R)); C.EmitReport(R); } return true; @@ -262,7 +263,8 @@ void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, new BugReport(*BT, BT->getName(), N); R->addRange(receiver->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - receiver)); + receiver, + R)); C.EmitReport(R); } return; @@ -308,7 +310,8 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, if (const Expr *receiver = msg.getInstanceReceiver()) { report->addRange(receiver->getSourceRange()); report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - receiver)); + receiver, + report)); } C.EmitReport(report); } diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 7e4761cdf8..81a27451cb 100644 --- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -34,28 +34,35 @@ public: void checkLocation(SVal location, bool isLoad, const Stmt* S, CheckerContext &C) const; - static void AddDerefSource(raw_ostream &os, + static const MemRegion *AddDerefSource(raw_ostream &os, SmallVectorImpl &Ranges, - const Expr *Ex, bool loadedFrom = false); + const Expr *Ex, const ProgramState *state, + const LocationContext *LCtx, + bool loadedFrom = false); }; } // end anonymous namespace -void DereferenceChecker::AddDerefSource(raw_ostream &os, - SmallVectorImpl &Ranges, - const Expr *Ex, - bool loadedFrom) { +const MemRegion * +DereferenceChecker::AddDerefSource(raw_ostream &os, + SmallVectorImpl &Ranges, + const Expr *Ex, + const ProgramState *state, + const LocationContext *LCtx, + bool loadedFrom) { Ex = Ex->IgnoreParenLValueCasts(); + const MemRegion *sourceR = 0; switch (Ex->getStmtClass()) { default: - return; + break; case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast(Ex); if (const VarDecl *VD = dyn_cast(DR->getDecl())) { os << " (" << (loadedFrom ? "loaded from" : "from") << " variable '" << VD->getName() << "')"; Ranges.push_back(DR->getSourceRange()); + sourceR = state->getLValue(VD, LCtx).getAsRegion(); } - return; + break; } case Stmt::MemberExprClass: { const MemberExpr *ME = cast(Ex); @@ -66,6 +73,7 @@ void DereferenceChecker::AddDerefSource(raw_ostream &os, break; } } + return sourceR; } void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, @@ -79,7 +87,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetDerefExpr(N))); + bugreporter::GetDerefExpr(N), report)); C.EmitReport(report); } return; @@ -92,6 +100,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, return; ProgramStateRef state = C.getState(); + const LocationContext *LCtx = C.getLocationContext(); ProgramStateRef notNullState, nullState; llvm::tie(notNullState, nullState) = state->assume(location); @@ -115,13 +124,17 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, // that syntactically caused the load. if (const Expr *expr = dyn_cast(S)) S = expr->IgnoreParenLValueCasts(); + + const MemRegion *sourceR = 0; switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { llvm::raw_svector_ostream os(buf); os << "Array access"; const ArraySubscriptExpr *AE = cast(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts()); + sourceR = + AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), + state.getPtr(), LCtx); os << " results in a null pointer dereference"; break; } @@ -129,7 +142,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, llvm::raw_svector_ostream os(buf); os << "Dereference of null pointer"; const UnaryOperator *U = cast(S); - AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true); + sourceR = + AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), + state.getPtr(), LCtx, true); break; } case Stmt::MemberExprClass: { @@ -138,7 +153,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, llvm::raw_svector_ostream os(buf); os << "Access to field '" << M->getMemberNameInfo() << "' results in a dereference of a null pointer"; - AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true); + sourceR = + AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), + state.getPtr(), LCtx, true); } break; } @@ -165,12 +182,17 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, N); report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetDerefExpr(N))); + bugreporter::GetDerefExpr(N), report)); for (SmallVectorImpl::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) report->addRange(*I); + if (sourceR) { + report->markInteresting(sourceR); + report->markInteresting(state->getRawSVal(loc::MemRegionVal(sourceR))); + } + C.EmitReport(report); return; } diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index ca71ca33a1..2627f0c982 100644 --- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -43,8 +43,7 @@ void DivZeroChecker::reportBug(const char *Msg, new BugReport(*BT, Msg, N); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - bugreporter::GetDenomExpr(N))); - + bugreporter::GetDenomExpr(N), R)); C.EmitReport(R); } } diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index b96bc66b6f..1b8dd6874c 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -121,6 +121,12 @@ private: SValBuilder &Builder) const { return definitelyReturnedError(RetSym, State, Builder, true); } + + /// Mark an AllocationPair interesting for diagnostic reporting. + void markInteresting(BugReport *R, const AllocationPair &AP) const { + R->markInteresting(AP.first); + R->markInteresting(AP.second->Region); + } /// The bug visitor which allows us to print extra diagnostics along the /// BugReport path. For example, showing the allocation site of the leaked @@ -282,6 +288,7 @@ void MacOSKeychainAPIChecker:: BugReport *Report = new BugReport(*BT, os.str(), N); Report->addVisitor(new SecKeychainBugVisitor(AP.first)); Report->addRange(ArgExpr->getSourceRange()); + markInteresting(Report, AP); C.EmitReport(Report); } @@ -318,6 +325,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, BugReport *Report = new BugReport(*BT, os.str(), N); Report->addVisitor(new SecKeychainBugVisitor(V)); Report->addRange(ArgExpr->getSourceRange()); + Report->markInteresting(AS->Region); C.EmitReport(Report); } } @@ -369,6 +377,8 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, BugReport *Report = new BugReport(*BT, "Trying to free data which has not been allocated.", N); Report->addRange(ArgExpr->getSourceRange()); + if (AS) + Report->markInteresting(AS->Region); C.EmitReport(Report); return; } @@ -432,6 +442,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, "Only call free if a valid (non-NULL) buffer was returned.", N); Report->addVisitor(new SecKeychainBugVisitor(ArgSM)); Report->addRange(ArgExpr->getSourceRange()); + Report->markInteresting(AS->Region); C.EmitReport(Report); return; } @@ -550,6 +561,7 @@ BugReport *MacOSKeychainAPIChecker:: BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing); Report->addVisitor(new SecKeychainBugVisitor(AP.first)); + markInteresting(Report, AP); return Report; } diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index c9f717059e..3f0d3d456e 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -535,6 +535,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, BugReport *R = new BugReport(*BT_DoubleFree, "Attempt to free released memory", N); R->addRange(ArgExpr->getSourceRange()); + R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); } @@ -667,6 +668,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, } BugReport *R = new BugReport(*BT_BadFree, os.str(), N); + R->markInteresting(MR); R->addRange(range); C.EmitReport(R); } @@ -820,6 +822,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, BugReport *R = new BugReport(*BT_Leak, "Memory is never released; potential memory leak", N, LocUsedForUniqueing); + R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); } @@ -964,6 +967,7 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, "Use of memory after it is freed",N); if (S) R->addRange(S->getSourceRange()); + R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); return true; diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index d70fdfd8e8..25caf98b6d 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -50,7 +50,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, "for @synchronized")); BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, + report)); C.EmitReport(report); } return; @@ -73,7 +74,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, "(no synchronization will occur)")); BugReport *report = new BugReport(*BT_null, BT_null->getDescription(), N); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, + report)); C.EmitReport(report); return; diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index f7dd6c2127..a59d1e4e4c 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -2165,9 +2165,7 @@ PathDiagnosticPiece* CFRefReportVisitor::getEndPath(BugReporterContext &BRC, const ExplodedNode *EndN, BugReport &BR) { - // Tell the BugReporterContext to report cases when the tracked symbol is - // assigned to different variables, etc. - BRC.addNotableSymbol(Sym); + BR.markInteresting(Sym); return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); } @@ -2178,7 +2176,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, // Tell the BugReporterContext to report cases when the tracked symbol is // assigned to different variables, etc. - BRC.addNotableSymbol(Sym); + BR.markInteresting(Sym); // We are reporting a leak. Walk up the graph to get to the first node where // the symbol appeared, and also get the first VarDecl that tracked object diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index c83d63d00a..7b1f0b139c 100644 --- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -54,7 +54,8 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, new BugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, RetE, + report)); C.EmitReport(report); } diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index e826a114e7..a30f6d5328 100644 --- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -99,7 +99,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, // Emit the bug report. BugReport *R = new BugReport(*BT, BT->getDescription(), N); - R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, R)); R->addRange(Ex->getSourceRange()); Ctx.EmitReport(R); diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 3161a21c93..c3c9ed7234 100644 --- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -76,10 +76,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, BugReport *report = new BugReport(*BT, OS.str(), N); if (Ex) { report->addRange(Ex->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex, + report)); } else - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B, + report)); C.EmitReport(report); } } diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index 9b9e4d5e36..0297c4eb14 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -43,7 +43,8 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(A->getIdx()->getSourceRange()); R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, - A->getIdx())); + A->getIdx(), + R)); C.EmitReport(R); } } diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 840ae3d2ad..78f7fa61b2 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -78,7 +78,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, BugReport *R = new BugReport(*BT, str, N); if (ex) { R->addRange(ex->getSourceRange()); - R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex)); + R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, ex, R)); } C.EmitReport(R); } diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 2211940d65..e68ab2a8b2 100644 --- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -224,7 +224,8 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, BugReport *report = new BugReport(*BT_mallocZero, os.str(), N); report->addRange(arg->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg, + report)); C.EmitReport(report); return true; diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 72b68c58bf..38c9cc1f33 100644 --- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -69,7 +69,8 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(SizeE->getSourceRange()); - report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SizeE)); + report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SizeE, + report)); C.EmitReport(report); return; } diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 53fedaf2a1..4ada636e8e 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -148,8 +148,9 @@ static bool RemoveUneededCalls(PathPieces &pieces) { PathDiagnosticEventPiece *event = cast(piece); // We never throw away an event, but we do throw it away wholesale // as part of a path if we throw the entire path away. - if (!event->isPrunable()) - containsSomethingInteresting = true; + if (event->isPrunable()) + continue; + containsSomethingInteresting = true; break; } case PathDiagnosticPiece::ControlFlow: @@ -376,190 +377,6 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { return PathDiagnosticLocation(S, SMgr, LC); } -//===----------------------------------------------------------------------===// -// ScanNotableSymbols: closure-like callback for scanning Store bindings. -//===----------------------------------------------------------------------===// - -static const VarDecl* GetMostRecentVarDeclBinding(const ExplodedNode *N, - ProgramStateManager& VMgr, - SVal X) { - - for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) { - - ProgramPoint P = N->getLocation(); - - if (!isa(P)) - continue; - - const DeclRefExpr *DR = dyn_cast(cast(P).getStmt()); - - if (!DR) - continue; - - SVal Y = N->getState()->getSVal(DR, N->getLocationContext()); - - if (X != Y) - continue; - - const VarDecl *VD = dyn_cast(DR->getDecl()); - - if (!VD) - continue; - - return VD; - } - - return 0; -} - -namespace { -class NotableSymbolHandler -: public StoreManager::BindingsHandler { - - SymbolRef Sym; - ProgramStateRef PrevSt; - const Stmt *S; - ProgramStateManager& VMgr; - const ExplodedNode *Pred; - PathDiagnostic& PD; - BugReporter& BR; - -public: - - NotableSymbolHandler(SymbolRef sym, - ProgramStateRef prevst, - const Stmt *s, - ProgramStateManager& vmgr, - const ExplodedNode *pred, - PathDiagnostic& pd, - BugReporter& br) - : Sym(sym), - PrevSt(prevst), - S(s), - VMgr(vmgr), - Pred(pred), - PD(pd), - BR(br) {} - - bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, - SVal V) { - - SymbolRef ScanSym = V.getAsSymbol(); - - if (ScanSym != Sym) - return true; - - // Check if the previous state has this binding. - SVal X = PrevSt->getSVal(loc::MemRegionVal(R)); - - if (X == V) // Same binding? - return true; - - // Different binding. Only handle assignments for now. We don't pull - // this check out of the loop because we will eventually handle other - // cases. - - VarDecl *VD = 0; - - if (const BinaryOperator* B = dyn_cast(S)) { - if (!B->isAssignmentOp()) - return true; - - // What variable did we assign to? - DeclRefExpr *DR = dyn_cast(B->getLHS()->IgnoreParenCasts()); - - if (!DR) - return true; - - VD = dyn_cast(DR->getDecl()); - } - else if (const DeclStmt *DS = dyn_cast(S)) { - // FIXME: Eventually CFGs won't have DeclStmts. Right now we - // assume that each DeclStmt has a single Decl. This invariant - // holds by construction in the CFG. - VD = dyn_cast(*DS->decl_begin()); - } - - if (!VD) - return true; - - // What is the most recently referenced variable with this binding? - const VarDecl *MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V); - - if (!MostRecent) - return true; - - // Create the diagnostic. - if (Loc::isLocType(VD->getType())) { - SmallString<64> buf; - llvm::raw_svector_ostream os(buf); - os << '\'' << *VD << "' now aliases '" << *MostRecent << '\''; - PathDiagnosticLocation L = - PathDiagnosticLocation::createBegin(S, BR.getSourceManager(), - Pred->getLocationContext()); - PD.getActivePath().push_front(new PathDiagnosticEventPiece(L, os.str())); - } - - return true; - } -}; -} - -static void HandleNotableSymbol(const ExplodedNode *N, - const Stmt *S, - SymbolRef Sym, BugReporter& BR, - PathDiagnostic& PD) { - - const ExplodedNode *Pred = N->pred_empty() ? 0 : *N->pred_begin(); - ProgramStateRef PrevSt = Pred ? Pred->getState() : 0; - - if (!PrevSt) - return; - - // Look at the region bindings of the current state that map to the - // specified symbol. Are any of them not in the previous state? - ProgramStateManager& VMgr = cast(BR).getStateManager(); - NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR); - cast(BR).getStateManager().iterBindings(N->getState(), H); -} - -namespace { -class ScanNotableSymbols -: public StoreManager::BindingsHandler { - - llvm::SmallSet AlreadyProcessed; - const ExplodedNode *N; - const Stmt *S; - GRBugReporter& BR; - PathDiagnostic& PD; - -public: - ScanNotableSymbols(const ExplodedNode *n, const Stmt *s, - GRBugReporter& br, PathDiagnostic& pd) - : N(n), S(s), BR(br), PD(pd) {} - - bool HandleBinding(StoreManager& SMgr, Store store, - const MemRegion* R, SVal V) { - - SymbolRef ScanSym = V.getAsSymbol(); - - if (!ScanSym) - return true; - - if (!BR.isNotable(ScanSym)) - return true; - - if (AlreadyProcessed.count(ScanSym)) - return true; - - AlreadyProcessed.insert(ScanSym); - - HandleNotableSymbol(N, S, ScanSym, BR, PD); - return true; - } -}; -} // end anonymous namespace - //===----------------------------------------------------------------------===// // "Minimal" path diagnostic generation algorithm. //===----------------------------------------------------------------------===// @@ -866,13 +683,6 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PD.getActivePath().push_front(p); } } - - if (const PostStmt *PS = dyn_cast(&P)) { - // Scan the region bindings, and see if a "notable" symbol has a new - // lval binding. - ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD); - PDB.getStateManager().iterBindings(N->getState(), SNS); - } } // After constructing the full PathDiagnostic, do a pass over it to compact @@ -1400,6 +1210,50 @@ void BugReport::Profile(llvm::FoldingSetNodeID& hash) const { } } +void BugReport::markInteresting(SymbolRef sym) { + if (!sym) + return; + interestingSymbols.insert(sym); +} + +void BugReport::markInteresting(const MemRegion *R) { + if (!R) + return; + R = R->getBaseRegion(); + interestingRegions.insert(R); + + if (const SymbolicRegion *SR = dyn_cast(R)) + interestingSymbols.insert(SR->getSymbol()); +} + +void BugReport::markInteresting(SVal V) { + markInteresting(V.getAsRegion()); + markInteresting(V.getAsSymbol()); +} + +bool BugReport::isInteresting(SVal V) const { + return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol()); +} + +bool BugReport::isInteresting(SymbolRef sym) const { + if (!sym) + return false; + return interestingSymbols.count(sym); +} + +bool BugReport::isInteresting(const MemRegion *R) const { + if (!R) + return false; + R = R->getBaseRegion(); + bool b = interestingRegions.count(R); + if (b) + return true; + if (const SymbolicRegion *SR = dyn_cast(R)) + return interestingSymbols.count(SR->getSymbol()); + return false; +} + + const Stmt *BugReport::getStmt() const { if (!ErrorNode) return 0; diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 1d29d5ff0a..09a9b41eae 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -287,7 +287,8 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, BugReporterVisitor * bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N, - const Stmt *S) { + const Stmt *S, + BugReport *report) { if (!S || !N) return 0; @@ -309,17 +310,19 @@ bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N, ProgramStateRef state = N->getState(); - // Walk through lvalue-to-rvalue conversions. - if (const DeclRefExpr *DR = dyn_cast(S)) { - if (const VarDecl *VD = dyn_cast(DR->getDecl())) { - const VarRegion *R = - StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); - - // What did we load? - SVal V = state->getSVal(loc::MemRegionVal(R)); + // Walk through lvalue-to-rvalue conversions. + const Expr *Ex = dyn_cast(S); + if (Ex) { + Ex = Ex->IgnoreParenLValueCasts(); + if (const DeclRefExpr *DR = dyn_cast(Ex)) { + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + const VarRegion *R = + StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); - if (isa(V) || isa(V) - || V.isUndef()) { + // What did we load? + SVal V = state->getSVal(loc::MemRegionVal(R)); + report->markInteresting(R); + report->markInteresting(V); return new FindLastStoreBRVisitor(V, R); } } @@ -339,7 +342,7 @@ bugreporter::getTrackNullOrUndefValueVisitor(const ExplodedNode *N, } if (R) { - assert(isa(R)); + report->markInteresting(R); return new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); } } @@ -386,7 +389,7 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, // The receiver was nil, and hence the method was skipped. // Register a BugReporterVisitor to issue a message telling us how // the receiver was null. - BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver)); + BR.addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Receiver, &BR)); // Issue a message saying that the method was skipped. PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), N->getLocationContext()); @@ -439,7 +442,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR); if (PathDiagnosticEventPiece *ev = dyn_cast_or_null(piece)) - ev->setPrunable(true); + ev->setPrunable(true, /* override */ false); return piece; } @@ -465,7 +468,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, if (const BlockEdge *BE = dyn_cast(&progPoint)) { const CFGBlock *srcBlk = BE->getSrc(); if (const Stmt *term = srcBlk->getTerminator()) - return VisitTerminator(term, N, srcBlk, BE->getDst(), BRC); + return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); return 0; } @@ -479,10 +482,10 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, const ProgramPointTag *tag = PS->getTag(); if (tag == tags.first) return VisitTrueTest(cast(PS->getStmt()), true, - BRC, N->getLocationContext()); + BRC, BR, N); if (tag == tags.second) return VisitTrueTest(cast(PS->getStmt()), false, - BRC, N->getLocationContext()); + BRC, BR, N); return 0; } @@ -495,6 +498,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk, const CFGBlock *dstBlk, + BugReport &R, BugReporterContext &BRC) { const Expr *Cond = 0; @@ -513,14 +517,15 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term, assert(srcBlk->succ_size() == 2); const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), - tookTrue, BRC, N->getLocationContext()); + tookTrue, BRC, R, N); } PathDiagnosticPiece * ConditionBRVisitor::VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC) { + BugReport &R, + const ExplodedNode *N) { const Expr *Ex = Cond; @@ -530,9 +535,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, default: return 0; case Stmt::BinaryOperatorClass: - return VisitTrueTest(Cond, cast(Ex), tookTrue, BRC, LC); + return VisitTrueTest(Cond, cast(Ex), tookTrue, BRC, + R, N); case Stmt::DeclRefExprClass: - return VisitTrueTest(Cond, cast(Ex), tookTrue, BRC, LC); + return VisitTrueTest(Cond, cast(Ex), tookTrue, BRC, + R, N); case Stmt::UnaryOperatorClass: { const UnaryOperator *UO = cast(Ex); if (UO->getOpcode() == UO_LNot) { @@ -547,14 +554,31 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, } bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, - BugReporterContext &BRC) { + BugReporterContext &BRC, + BugReport &report, + const ExplodedNode *N, + llvm::Optional &prunable) { const Expr *OriginalExpr = Ex; Ex = Ex->IgnoreParenCasts(); if (const DeclRefExpr *DR = dyn_cast(Ex)) { const bool quotes = isa(DR->getDecl()); - if (quotes) + if (quotes) { Out << '\''; + const LocationContext *LCtx = N->getLocationContext(); + const ProgramState *state = N->getState().getPtr(); + if (const MemRegion *R = state->getLValue(cast(DR->getDecl()), + LCtx).getAsRegion()) { + if (report.isInteresting(R)) + prunable = false; + else { + const ProgramState *state = N->getState().getPtr(); + SVal V = state->getSVal(R); + if (report.isInteresting(V)) + prunable = false; + } + } + } Out << DR->getDecl()->getDeclName().getAsString(); if (quotes) Out << '\''; @@ -588,15 +612,19 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, const bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC) { + BugReport &R, + const ExplodedNode *N) { bool shouldInvert = false; + llvm::Optional shouldPrune; SmallString<128> LhsString, RhsString; { - llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); - const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC); - const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC); + llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); + const bool isVarLHS = patternMatch(BExpr->getLHS(), OutLHS, BRC, R, N, + shouldPrune); + const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N, + shouldPrune); shouldInvert = !isVarLHS && isVarRHS; } @@ -607,7 +635,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, // For assignment operators, all that we care about is that the LHS // evaluates to "true" or "false". return VisitConditionVariable(LhsString, BExpr->getLHS(), tookTrue, - BRC, LC); + BRC, R, N); } // For non-assignment operations, we require that we can understand @@ -655,9 +683,13 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, } Out << (shouldInvert ? LhsString : RhsString); - - PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); - return new PathDiagnosticEventPiece(Loc, Out.str()); + const LocationContext *LCtx = N->getLocationContext(); + PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); + PathDiagnosticEventPiece *event = + new PathDiagnosticEventPiece(Loc, Out.str()); + if (shouldPrune.hasValue()) + event->setPrunable(shouldPrune.getValue()); + return event; } PathDiagnosticPiece * @@ -665,7 +697,8 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, const bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC) { + BugReport &report, + const ExplodedNode *N) { SmallString<256> buf; llvm::raw_svector_ostream Out(buf); Out << "Assuming " << LhsString << " is "; @@ -683,8 +716,22 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, else return 0; - PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LC); - return new PathDiagnosticEventPiece(Loc, Out.str()); + const LocationContext *LCtx = N->getLocationContext(); + PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); + PathDiagnosticEventPiece *event = + new PathDiagnosticEventPiece(Loc, Out.str()); + + if (const DeclRefExpr *DR = dyn_cast(CondVarExpr)) { + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + const ProgramState *state = N->getState().getPtr(); + if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { + if (report.isInteresting(R)) + event->setPrunable(false); + } + } + } + + return event; } PathDiagnosticPiece * @@ -692,7 +739,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, BugReporterContext &BRC, - const LocationContext *LC) { + BugReport &report, + const ExplodedNode *N) { const VarDecl *VD = dyn_cast(DR->getDecl()); if (!VD) @@ -716,7 +764,21 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, else return 0; - PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); - return new PathDiagnosticEventPiece(Loc, Out.str()); + const LocationContext *LCtx = N->getLocationContext(); + PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); + PathDiagnosticEventPiece *event = + new PathDiagnosticEventPiece(Loc, Out.str()); + + const ProgramState *state = N->getState().getPtr(); + if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { + if (report.isInteresting(R)) + event->setPrunable(false); + else { + SVal V = state->getSVal(R); + if (report.isInteresting(V)) + event->setPrunable(false); + } + } + return event; } diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c index ceb444361c..9d71d714fb 100644 --- a/test/Analysis/malloc-plist.c +++ b/test/Analysis/malloc-plist.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-output=plist -o - %s | FileCheck %s +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-output=plist -o %t %s +// RUN: FileCheck --input-file %t %s typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); @@ -23,6 +24,8 @@ void reallocDiagnostics() { char * buf = malloc(100); char * tmp; tmp = (char*)realloc(buf, 0x1000000); + // FIXME: we need a diagnostic for the null check. + // This requires propagating "interesting" for 'tmp'. if (!tmp) { return;// expected-warning {{leak}} } @@ -30,8 +33,20 @@ void reallocDiagnostics() { free(buf); } +void *wrapper() { + void *x = malloc(100); + // This is intentionally done to test diagnostic emission. + if (x) + return x; + return 0; +} + +void test_wrapper() { + void *buf = wrapper(); + (void) buf; +} + // CHECK: -// CHECK: // CHECK: // CHECK: // CHECK: files @@ -50,12 +65,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col5 // CHECK: file0 // CHECK: @@ -63,12 +78,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: @@ -77,34 +92,6 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line9 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col9 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line9 -// CHECK: col14 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: extended_message -// CHECK: Assuming 'in' is > 5 -// CHECK: message -// CHECK: Assuming 'in' is > 5 -// CHECK: -// CHECK: // CHECK: kindcontrol // CHECK: edges // CHECK: @@ -112,12 +99,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: @@ -125,12 +112,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col9 // CHECK: file0 // CHECK: @@ -146,12 +133,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col9 // CHECK: file0 // CHECK: @@ -159,12 +146,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col27 // CHECK: file0 // CHECK: @@ -176,7 +163,7 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col18 // CHECK: file0 // CHECK: @@ -184,12 +171,12 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col27 // CHECK: file0 // CHECK: @@ -208,12 +195,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line10 +// CHECK: line11 // CHECK: col27 // CHECK: file0 // CHECK: @@ -221,12 +208,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line13 +// CHECK: line14 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line13 +// CHECK: line14 // CHECK: col6 // CHECK: file0 // CHECK: @@ -238,7 +225,7 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line13 +// CHECK: line14 // CHECK: col5 // CHECK: file0 // CHECK: @@ -246,12 +233,12 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: line13 +// CHECK: line14 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line13 +// CHECK: line14 // CHECK: col6 // CHECK: file0 // CHECK: @@ -268,7 +255,7 @@ void reallocDiagnostics() { // CHECK: typeMemory leak // CHECK: location // CHECK: -// CHECK: line13 +// CHECK: line14 // CHECK: col5 // CHECK: file0 // CHECK: @@ -284,12 +271,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line17 +// CHECK: line18 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line17 +// CHECK: line18 // CHECK: col5 // CHECK: file0 // CHECK: @@ -297,12 +284,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col5 // CHECK: file0 // CHECK: @@ -318,12 +305,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col5 // CHECK: file0 // CHECK: @@ -331,12 +318,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col30 // CHECK: file0 // CHECK: @@ -348,7 +335,7 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col9 // CHECK: file0 // CHECK: @@ -356,12 +343,12 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col30 // CHECK: file0 // CHECK: @@ -380,12 +367,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col30 // CHECK: file0 // CHECK: @@ -393,12 +380,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line20 +// CHECK: line21 // CHECK: col1 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line20 +// CHECK: line21 // CHECK: col1 // CHECK: file0 // CHECK: @@ -410,7 +397,7 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line20 +// CHECK: line21 // CHECK: col1 // CHECK: file0 // CHECK: @@ -425,7 +412,7 @@ void reallocDiagnostics() { // CHECK: typeMemory leak // CHECK: location // CHECK: -// CHECK: line20 +// CHECK: line21 // CHECK: col1 // CHECK: file0 // CHECK: @@ -441,12 +428,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col5 // CHECK: file0 // CHECK: @@ -454,12 +441,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col28 // CHECK: file0 // CHECK: @@ -471,7 +458,7 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col18 // CHECK: file0 // CHECK: @@ -479,12 +466,12 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col28 // CHECK: file0 // CHECK: @@ -503,12 +490,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col28 // CHECK: file0 // CHECK: @@ -516,12 +503,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col5 // CHECK: file0 // CHECK: @@ -537,12 +524,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col5 // CHECK: file0 // CHECK: @@ -550,12 +537,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col40 // CHECK: file0 // CHECK: @@ -567,7 +554,7 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col18 // CHECK: file0 // CHECK: @@ -575,12 +562,12 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col40 // CHECK: file0 // CHECK: @@ -599,12 +586,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line25 +// CHECK: line26 // CHECK: col40 // CHECK: file0 // CHECK: @@ -612,12 +599,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col6 // CHECK: file0 // CHECK: @@ -629,7 +616,7 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col5 // CHECK: file0 // CHECK: @@ -637,12 +624,12 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col6 // CHECK: file0 // CHECK: @@ -661,12 +648,12 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col6 // CHECK: file0 // CHECK: @@ -674,12 +661,12 @@ void reallocDiagnostics() { // CHECK: end // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line29 // CHECK: col12 // CHECK: file0 // CHECK: @@ -688,10 +675,44 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line29 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line29 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line30 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line30 +// CHECK: col14 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line26 +// CHECK: line30 // CHECK: col9 // CHECK: file0 // CHECK: @@ -699,22 +720,36 @@ void reallocDiagnostics() { // CHECK: // CHECK: // CHECK: -// CHECK: line26 +// CHECK: line30 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line26 -// CHECK: col12 +// CHECK: line30 +// CHECK: col14 // CHECK: file0 // CHECK: // CHECK: // CHECK: // CHECK: extended_message -// CHECK: Assuming 'tmp' is null +// CHECK: Memory is never released; potential memory leak // CHECK: message -// CHECK: Assuming 'tmp' is null +// CHECK: Memory is never released; potential memory leak // CHECK: +// CHECK: +// CHECK: descriptionMemory is never released; potential memory leak +// CHECK: categoryMemory Error +// CHECK: typeMemory leak +// CHECK: location +// CHECK: +// CHECK: line30 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: path +// CHECK: // CHECK: // CHECK: kindcontrol // CHECK: edges @@ -723,26 +758,26 @@ void reallocDiagnostics() { // CHECK: start // CHECK: // CHECK: -// CHECK: line26 -// CHECK: col9 +// CHECK: line45 +// CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line26 -// CHECK: col12 +// CHECK: line45 +// CHECK: col3 // CHECK: file0 // CHECK: // CHECK: // CHECK: end // CHECK: // CHECK: -// CHECK: line27 -// CHECK: col9 +// CHECK: line45 +// CHECK: col15 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line27 -// CHECK: col14 +// CHECK: line45 +// CHECK: col15 // CHECK: file0 // CHECK: // CHECK: @@ -753,26 +788,340 @@ void reallocDiagnostics() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line27 -// CHECK: col9 +// CHECK: line45 +// CHECK: col15 // CHECK: file0 // CHECK: // CHECK: ranges // CHECK: // CHECK: // CHECK: -// CHECK: line27 -// CHECK: col9 +// CHECK: line45 +// CHECK: col15 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line27 -// CHECK: col14 +// CHECK: line45 +// CHECK: col23 // CHECK: file0 // CHECK: // CHECK: // CHECK: // CHECK: extended_message +// CHECK: Calling 'wrapper' +// CHECK: message +// CHECK: Calling 'wrapper' +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line36 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: extended_message +// CHECK: Entered call to 'wrapper' +// CHECK: message +// CHECK: Entered call to 'wrapper' +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line36 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line36 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col13 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col23 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line37 +// CHECK: col13 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col13 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col23 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Memory is allocated +// CHECK: message +// CHECK: Memory is allocated +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col13 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col23 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line39 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Assuming 'x' is non-null +// CHECK: message +// CHECK: Assuming 'x' is non-null +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line39 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line40 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line40 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line45 +// CHECK: col15 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line45 +// CHECK: col15 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line45 +// CHECK: col23 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Returning to 'test_wrapper' +// CHECK: message +// CHECK: Returning to 'test_wrapper' +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line45 +// CHECK: col15 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line45 +// CHECK: col23 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line47 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line47 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line47 +// CHECK: col1 +// CHECK: file0 +// CHECK: +// CHECK: extended_message // CHECK: Memory is never released; potential memory leak // CHECK: message // CHECK: Memory is never released; potential memory leak @@ -783,8 +1132,8 @@ void reallocDiagnostics() { // CHECK: typeMemory leak // CHECK: location // CHECK: -// CHECK: line27 -// CHECK: col9 +// CHECK: line47 +// CHECK: col1 // CHECK: file0 // CHECK: // CHECK: diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m index d619a7aa38..750c309e06 100644 --- a/test/Analysis/plist-output-alternate.m +++ b/test/Analysis/plist-output-alternate.m @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o %t %s +// RUN: FileCheck --input-file %t %s void test_null_init(void) { int *p = 0; @@ -57,7 +58,6 @@ void rdar8331641(int x) { } // CHECK: -// CHECK: // CHECK: // CHECK: // CHECK: files @@ -76,12 +76,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line4 +// CHECK: line5 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line4 +// CHECK: line5 // CHECK: col3 // CHECK: file0 // CHECK: @@ -89,12 +89,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line5 +// CHECK: line6 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line5 +// CHECK: line6 // CHECK: col4 // CHECK: file0 // CHECK: @@ -106,7 +106,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line5 +// CHECK: line6 // CHECK: col3 // CHECK: file0 // CHECK: @@ -114,12 +114,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line5 +// CHECK: line6 // CHECK: col4 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line5 +// CHECK: line6 // CHECK: col4 // CHECK: file0 // CHECK: @@ -136,7 +136,7 @@ void rdar8331641(int x) { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line5 +// CHECK: line6 // CHECK: col3 // CHECK: file0 // CHECK: @@ -152,12 +152,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line9 +// CHECK: line10 // CHECK: col3 // CHECK: file0 // CHECK: @@ -165,12 +165,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line12 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line12 // CHECK: col4 // CHECK: file0 // CHECK: @@ -182,7 +182,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line11 +// CHECK: line12 // CHECK: col3 // CHECK: file0 // CHECK: @@ -190,12 +190,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line12 // CHECK: col4 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line12 // CHECK: col4 // CHECK: file0 // CHECK: @@ -212,7 +212,7 @@ void rdar8331641(int x) { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line11 +// CHECK: line12 // CHECK: col3 // CHECK: file0 // CHECK: @@ -228,12 +228,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line15 +// CHECK: line16 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line15 +// CHECK: line16 // CHECK: col3 // CHECK: file0 // CHECK: @@ -241,12 +241,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col4 // CHECK: file0 // CHECK: @@ -258,7 +258,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col3 // CHECK: file0 // CHECK: @@ -266,12 +266,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col4 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col4 // CHECK: file0 // CHECK: @@ -288,7 +288,7 @@ void rdar8331641(int x) { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line18 +// CHECK: line19 // CHECK: col3 // CHECK: file0 // CHECK: @@ -304,12 +304,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col3 // CHECK: file0 // CHECK: @@ -317,12 +317,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col8 // CHECK: file0 // CHECK: @@ -334,7 +334,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col7 // CHECK: file0 // CHECK: @@ -342,12 +342,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col8 // CHECK: file0 // CHECK: @@ -366,12 +366,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line22 +// CHECK: line23 // CHECK: col8 // CHECK: file0 // CHECK: @@ -379,12 +379,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col6 // CHECK: file0 // CHECK: @@ -396,7 +396,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col5 // CHECK: file0 // CHECK: @@ -404,12 +404,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col6 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col6 // CHECK: file0 // CHECK: @@ -426,7 +426,7 @@ void rdar8331641(int x) { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line23 +// CHECK: line24 // CHECK: col5 // CHECK: file0 // CHECK: @@ -442,12 +442,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line28 +// CHECK: line29 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line28 +// CHECK: line29 // CHECK: col3 // CHECK: file0 // CHECK: @@ -455,12 +455,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line28 +// CHECK: line29 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line28 +// CHECK: line29 // CHECK: col8 // CHECK: file0 // CHECK: @@ -469,34 +469,6 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line28 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: extended_message -// CHECK: Assuming 'q' is null -// CHECK: message -// CHECK: Assuming 'q' is null -// CHECK: -// CHECK: // CHECK: kindcontrol // CHECK: edges // CHECK: @@ -504,12 +476,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line28 +// CHECK: line29 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line28 +// CHECK: line29 // CHECK: col8 // CHECK: file0 // CHECK: @@ -517,12 +489,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line29 +// CHECK: line30 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line29 +// CHECK: line30 // CHECK: col5 // CHECK: file0 // CHECK: @@ -538,12 +510,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line29 +// CHECK: line30 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line29 +// CHECK: line30 // CHECK: col5 // CHECK: file0 // CHECK: @@ -551,12 +523,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col6 // CHECK: file0 // CHECK: @@ -568,7 +540,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col5 // CHECK: file0 // CHECK: @@ -576,12 +548,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col6 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col6 // CHECK: file0 // CHECK: @@ -598,7 +570,7 @@ void rdar8331641(int x) { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col5 // CHECK: file0 // CHECK: @@ -614,12 +586,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line35 +// CHECK: line36 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line35 +// CHECK: line36 // CHECK: col3 // CHECK: file0 // CHECK: @@ -627,12 +599,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line35 +// CHECK: line36 // CHECK: col10 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line35 +// CHECK: line36 // CHECK: col10 // CHECK: file0 // CHECK: @@ -648,12 +620,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line35 +// CHECK: line36 // CHECK: col10 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line35 +// CHECK: line36 // CHECK: col10 // CHECK: file0 // CHECK: @@ -661,12 +633,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line37 +// CHECK: line38 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line37 +// CHECK: line38 // CHECK: col8 // CHECK: file0 // CHECK: @@ -678,7 +650,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line37 +// CHECK: line38 // CHECK: col3 // CHECK: file0 // CHECK: @@ -686,12 +658,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line37 +// CHECK: line38 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line37 +// CHECK: line38 // CHECK: col7 // CHECK: file0 // CHECK: @@ -708,7 +680,7 @@ void rdar8331641(int x) { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line37 +// CHECK: line38 // CHECK: col3 // CHECK: file0 // CHECK: @@ -724,12 +696,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line52 +// CHECK: line53 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line52 +// CHECK: line53 // CHECK: col3 // CHECK: file0 // CHECK: @@ -737,12 +709,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col3 // CHECK: file0 // CHECK: @@ -758,12 +730,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col3 // CHECK: file0 // CHECK: @@ -771,12 +743,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col23 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col82 // CHECK: file0 // CHECK: @@ -788,7 +760,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col23 // CHECK: file0 // CHECK: @@ -796,12 +768,12 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col23 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col82 // CHECK: file0 // CHECK: @@ -820,12 +792,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col23 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line53 +// CHECK: line54 // CHECK: col82 // CHECK: file0 // CHECK: @@ -833,12 +805,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col3 // CHECK: file0 // CHECK: @@ -854,12 +826,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col3 // CHECK: file0 // CHECK: @@ -867,12 +839,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col7 // CHECK: file0 // CHECK: @@ -881,34 +853,6 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line54 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line54 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: extended_message -// CHECK: Assuming 'x' is 0 -// CHECK: message -// CHECK: Assuming 'x' is 0 -// CHECK: -// CHECK: // CHECK: kindcontrol // CHECK: edges // CHECK: @@ -916,12 +860,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line54 +// CHECK: line55 // CHECK: col7 // CHECK: file0 // CHECK: @@ -929,12 +873,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col10 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col10 // CHECK: file0 // CHECK: @@ -950,12 +894,12 @@ void rdar8331641(int x) { // CHECK: start // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col10 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col10 // CHECK: file0 // CHECK: @@ -963,12 +907,12 @@ void rdar8331641(int x) { // CHECK: end // CHECK: // CHECK: -// CHECK: line57 +// CHECK: line58 // CHECK: col1 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line57 +// CHECK: line58 // CHECK: col1 // CHECK: file0 // CHECK: @@ -980,7 +924,7 @@ void rdar8331641(int x) { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line57 +// CHECK: line58 // CHECK: col1 // CHECK: file0 // CHECK: @@ -995,7 +939,7 @@ void rdar8331641(int x) { // CHECK: typeLeak // CHECK: location // CHECK: -// CHECK: line57 +// CHECK: line58 // CHECK: col1 // CHECK: file0 // CHECK: diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m index 691d6e60f2..375d234207 100644 --- a/test/Analysis/plist-output.m +++ b/test/Analysis/plist-output.m @@ -24,9 +24,10 @@ void test_null_cond(int *p) { *p = 0xDEADBEEF; } } - + void test_null_cond_transitive(int *q) { if (!q) { + // FIXME: we need a diagnostic saying that p is initialized to 0 int *p = q; *p = 0xDEADBEEF; } @@ -80,7 +81,6 @@ int test_cond_assign() { @end // CHECK: -// CHECK: // CHECK: // CHECK: // CHECK: files @@ -492,34 +492,6 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line29 -// CHECK: col8 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: extended_message -// CHECK: Assuming 'q' is null -// CHECK: message -// CHECK: Assuming 'q' is null -// CHECK: -// CHECK: // CHECK: kindcontrol // CHECK: edges // CHECK: @@ -540,12 +512,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col5 // CHECK: file0 // CHECK: @@ -561,12 +533,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line30 +// CHECK: line31 // CHECK: col5 // CHECK: file0 // CHECK: @@ -574,12 +546,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line31 +// CHECK: line32 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line31 +// CHECK: line32 // CHECK: col6 // CHECK: file0 // CHECK: @@ -591,7 +563,7 @@ int test_cond_assign() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line31 +// CHECK: line32 // CHECK: col5 // CHECK: file0 // CHECK: @@ -599,12 +571,12 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: line31 +// CHECK: line32 // CHECK: col6 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line31 +// CHECK: line32 // CHECK: col6 // CHECK: file0 // CHECK: @@ -621,7 +593,7 @@ int test_cond_assign() { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line31 +// CHECK: line32 // CHECK: col5 // CHECK: file0 // CHECK: @@ -637,12 +609,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line36 +// CHECK: line37 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line36 +// CHECK: line37 // CHECK: col3 // CHECK: file0 // CHECK: @@ -650,12 +622,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line36 +// CHECK: line37 // CHECK: col10 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line36 +// CHECK: line37 // CHECK: col10 // CHECK: file0 // CHECK: @@ -671,12 +643,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line36 +// CHECK: line37 // CHECK: col10 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line36 +// CHECK: line37 // CHECK: col10 // CHECK: file0 // CHECK: @@ -684,12 +656,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line38 +// CHECK: line39 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line38 +// CHECK: line39 // CHECK: col8 // CHECK: file0 // CHECK: @@ -701,7 +673,7 @@ int test_cond_assign() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line38 +// CHECK: line39 // CHECK: col3 // CHECK: file0 // CHECK: @@ -709,12 +681,12 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: line38 +// CHECK: line39 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line38 +// CHECK: line39 // CHECK: col7 // CHECK: file0 // CHECK: @@ -731,7 +703,7 @@ int test_cond_assign() { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line38 +// CHECK: line39 // CHECK: col3 // CHECK: file0 // CHECK: @@ -747,12 +719,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line43 +// CHECK: line44 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line43 +// CHECK: line44 // CHECK: col3 // CHECK: file0 // CHECK: @@ -760,12 +732,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line43 +// CHECK: line44 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line43 +// CHECK: line44 // CHECK: col7 // CHECK: file0 // CHECK: @@ -774,34 +746,6 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line43 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line43 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: extended_message -// CHECK: Assuming 'a' is not equal to 0 -// CHECK: message -// CHECK: Assuming 'a' is not equal to 0 -// CHECK: -// CHECK: // CHECK: kindcontrol // CHECK: edges // CHECK: @@ -809,12 +753,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line43 +// CHECK: line44 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line43 +// CHECK: line44 // CHECK: col7 // CHECK: file0 // CHECK: @@ -822,12 +766,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col3 // CHECK: file0 // CHECK: @@ -843,12 +787,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col3 // CHECK: file0 // CHECK: @@ -856,12 +800,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col7 // CHECK: file0 // CHECK: @@ -870,34 +814,6 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: kindevent -// CHECK: location -// CHECK: -// CHECK: line46 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: ranges -// CHECK: -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col7 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: line46 -// CHECK: col12 -// CHECK: file0 -// CHECK: -// CHECK: -// CHECK: -// CHECK: extended_message -// CHECK: Assuming 'b' is equal to 0 -// CHECK: message -// CHECK: Assuming 'b' is equal to 0 -// CHECK: -// CHECK: // CHECK: kindcontrol // CHECK: edges // CHECK: @@ -905,12 +821,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line46 +// CHECK: line47 // CHECK: col7 // CHECK: file0 // CHECK: @@ -918,12 +834,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line49 +// CHECK: line50 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line49 +// CHECK: line50 // CHECK: col3 // CHECK: file0 // CHECK: @@ -939,12 +855,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line49 +// CHECK: line50 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line49 +// CHECK: line50 // CHECK: col3 // CHECK: file0 // CHECK: @@ -952,12 +868,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line50 +// CHECK: line51 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line50 +// CHECK: line51 // CHECK: col4 // CHECK: file0 // CHECK: @@ -969,7 +885,7 @@ int test_cond_assign() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line50 +// CHECK: line51 // CHECK: col3 // CHECK: file0 // CHECK: @@ -977,12 +893,12 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: line50 +// CHECK: line51 // CHECK: col4 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line50 +// CHECK: line51 // CHECK: col4 // CHECK: file0 // CHECK: @@ -999,7 +915,7 @@ int test_cond_assign() { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line50 +// CHECK: line51 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1015,12 +931,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line55 +// CHECK: line56 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line55 +// CHECK: line56 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1028,12 +944,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1049,12 +965,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1062,12 +978,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col7 // CHECK: file0 // CHECK: @@ -1079,7 +995,7 @@ int test_cond_assign() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col7 // CHECK: file0 // CHECK: @@ -1087,12 +1003,12 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col7 // CHECK: file0 // CHECK: @@ -1111,12 +1027,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line56 +// CHECK: line57 // CHECK: col7 // CHECK: file0 // CHECK: @@ -1124,12 +1040,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1145,12 +1061,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1158,12 +1074,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col10 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col11 // CHECK: file0 // CHECK: @@ -1175,7 +1091,7 @@ int test_cond_assign() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col10 // CHECK: file0 // CHECK: @@ -1183,12 +1099,12 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col11 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col11 // CHECK: file0 // CHECK: @@ -1205,7 +1121,7 @@ int test_cond_assign() { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line58 +// CHECK: line59 // CHECK: col10 // CHECK: file0 // CHECK: @@ -1221,12 +1137,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1234,12 +1150,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col7 // CHECK: file0 // CHECK: @@ -1255,12 +1171,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col7 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col7 // CHECK: file0 // CHECK: @@ -1268,12 +1184,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1289,12 +1205,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col3 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line75 +// CHECK: line76 // CHECK: col3 // CHECK: file0 // CHECK: @@ -1302,12 +1218,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line76 +// CHECK: line77 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line76 +// CHECK: line77 // CHECK: col5 // CHECK: file0 // CHECK: @@ -1323,12 +1239,12 @@ int test_cond_assign() { // CHECK: start // CHECK: // CHECK: -// CHECK: line76 +// CHECK: line77 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line76 +// CHECK: line77 // CHECK: col5 // CHECK: file0 // CHECK: @@ -1336,12 +1252,12 @@ int test_cond_assign() { // CHECK: end // CHECK: // CHECK: -// CHECK: line77 +// CHECK: line78 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line77 +// CHECK: line78 // CHECK: col6 // CHECK: file0 // CHECK: @@ -1353,7 +1269,7 @@ int test_cond_assign() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line77 +// CHECK: line78 // CHECK: col5 // CHECK: file0 // CHECK: @@ -1361,12 +1277,12 @@ int test_cond_assign() { // CHECK: // CHECK: // CHECK: -// CHECK: line77 +// CHECK: line78 // CHECK: col6 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line77 +// CHECK: line78 // CHECK: col6 // CHECK: file0 // CHECK: @@ -1383,7 +1299,7 @@ int test_cond_assign() { // CHECK: typeDereference of null pointer // CHECK: location // CHECK: -// CHECK: line77 +// CHECK: line78 // CHECK: col5 // CHECK: file0 // CHECK: @@ -1392,3 +1308,4 @@ int test_cond_assign() { // CHECK: // CHECK: +