diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
| commit | 809500fc2c13c8173a16b052304d983864e4a1e1 (patch) | |
| tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | |
| parent | be7c9ec198dcdb5bf73a35bfbb00b3333cb87909 (diff) | |
Notes
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporterVisitors.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 842 |
1 files changed, 588 insertions, 254 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 328e8a650df1d..f600362da94b7 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -12,22 +12,23 @@ // //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" - #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; +using llvm::FoldingSetNodeID; + //===----------------------------------------------------------------------===// // Utility functions. //===----------------------------------------------------------------------===// @@ -39,37 +40,33 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) { return false; } -const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) { +const Expr *bugreporter::getDerefExpr(const Stmt *S) { // Pattern match for a few useful cases (do something smarter later): // a[0], p->f, *p - const PostStmt *Loc = N->getLocationAs<PostStmt>(); - if (!Loc) - return 0; - - const Expr *S = dyn_cast<Expr>(Loc->getStmt()); - if (!S) + const Expr *E = dyn_cast<Expr>(S); + if (!E) return 0; - S = S->IgnoreParenCasts(); + E = E->IgnoreParenCasts(); while (true) { - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) { + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) { assert(B->isAssignmentOp()); - S = B->getLHS()->IgnoreParenCasts(); + E = B->getLHS()->IgnoreParenCasts(); continue; } - else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) { + else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) { if (U->getOpcode() == UO_Deref) return U->getSubExpr()->IgnoreParenCasts(); } - else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) { + else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { return ME->getBase()->IgnoreParenCasts(); } } - else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(S)) { + else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { return IvarRef->getBase()->IgnoreParenCasts(); } - else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) { + else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) { return AE->getBase(); } break; @@ -137,13 +134,15 @@ class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> { const StackFrameContext *StackFrame; enum { Initial, - MaybeSuppress, + MaybeUnsuppress, Satisfied } Mode; + bool EnableNullFPSuppression; + public: - ReturnVisitor(const StackFrameContext *Frame) - : StackFrame(Frame), Mode(Initial) {} + ReturnVisitor(const StackFrameContext *Frame, bool Suppressed) + : StackFrame(Frame), Mode(Initial), EnableNullFPSuppression(Suppressed) {} static void *getTag() { static int Tag = 0; @@ -153,6 +152,7 @@ public: virtual void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(ReturnVisitor::getTag()); ID.AddPointer(StackFrame); + ID.AddBoolean(EnableNullFPSuppression); } /// Adds a ReturnVisitor if the given statement represents a call that was @@ -163,16 +163,17 @@ public: /// the statement is a call that was inlined, we add the visitor to the /// bug report, so it can print a note later. static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S, - BugReport &BR) { + BugReport &BR, + bool InEnableNullFPSuppression) { if (!CallEvent::isCallStmt(S)) return; // First, find when we processed the statement. do { - if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) + if (Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>()) if (CEE->getCalleeContext()->getCallSite() == S) break; - if (const StmtPoint *SP = Node->getLocationAs<StmtPoint>()) + if (Optional<StmtPoint> SP = Node->getLocationAs<StmtPoint>()) if (SP->getStmt() == S) break; @@ -180,19 +181,41 @@ public: } while (Node); // Next, step over any post-statement checks. - while (Node && isa<PostStmt>(Node->getLocation())) + while (Node && Node->getLocation().getAs<PostStmt>()) Node = Node->getFirstPred(); + if (!Node) + return; // Finally, see if we inlined the call. - if (Node) { - if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) { - const StackFrameContext *CalleeContext = CEE->getCalleeContext(); - if (CalleeContext->getCallSite() == S) { - BR.markInteresting(CalleeContext); - BR.addVisitor(new ReturnVisitor(CalleeContext)); - } - } - } + Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>(); + if (!CEE) + return; + + const StackFrameContext *CalleeContext = CEE->getCalleeContext(); + if (CalleeContext->getCallSite() != S) + return; + + // Check the return value. + ProgramStateRef State = Node->getState(); + SVal RetVal = State->getSVal(S, Node->getLocationContext()); + + // Handle cases where a reference is returned and then immediately used. + if (cast<Expr>(S)->isGLValue()) + if (Optional<Loc> LValue = RetVal.getAs<Loc>()) + RetVal = State->getSVal(*LValue); + + // See if the return value is NULL. If so, suppress the report. + SubEngine *Eng = State->getStateManager().getOwningEngine(); + assert(Eng && "Cannot file a bug report without an owning engine"); + AnalyzerOptions &Options = Eng->getAnalysisManager().options; + + bool EnableNullFPSuppression = false; + if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths()) + if (Optional<Loc> RetLoc = RetVal.getAs<Loc>()) + EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue(); + + BR.markInteresting(CalleeContext); + BR.addVisitor(new ReturnVisitor(CalleeContext, EnableNullFPSuppression)); } /// Returns true if any counter-suppression heuristics are enabled for @@ -209,7 +232,7 @@ public: if (N->getLocationContext() != StackFrame) return 0; - const StmtPoint *SP = N->getLocationAs<StmtPoint>(); + Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>(); if (!SP) return 0; @@ -229,35 +252,49 @@ public: const Expr *RetE = Ret->getRetValue(); assert(RetE && "Tracking a return value for a void function"); + + // Handle cases where a reference is returned and then immediately used. + Optional<Loc> LValue; + if (RetE->isGLValue()) { + if ((LValue = V.getAs<Loc>())) { + SVal RValue = State->getRawSVal(*LValue, RetE->getType()); + if (RValue.getAs<DefinedSVal>()) + V = RValue; + } + } + + // Ignore aggregate rvalues. + if (V.getAs<nonloc::LazyCompoundVal>() || + V.getAs<nonloc::CompoundVal>()) + return 0; + RetE = RetE->IgnoreParenCasts(); // If we can't prove the return value is 0, just mark it interesting, and // make sure to track it into any further inner functions. - if (State->assume(cast<DefinedSVal>(V), true)) { + if (!State->isNull(V).isConstrainedTrue()) { BR.markInteresting(V); - ReturnVisitor::addVisitorIfNecessary(N, RetE, BR); + ReturnVisitor::addVisitorIfNecessary(N, RetE, BR, + EnableNullFPSuppression); return 0; } // If we're returning 0, we should track where that 0 came from. - bugreporter::trackNullOrUndefValue(N, RetE, BR); + bugreporter::trackNullOrUndefValue(N, RetE, BR, /*IsArg*/ false, + EnableNullFPSuppression); // Build an appropriate message based on the return value. SmallString<64> Msg; llvm::raw_svector_ostream Out(Msg); - if (isa<Loc>(V)) { - // If we are pruning null-return paths as unlikely error paths, mark the - // report invalid. We still want to emit a path note, however, in case + if (V.getAs<Loc>()) { + // If we have counter-suppression enabled, make sure we keep visiting + // future nodes. We want to emit a path note as well, in case // the report is resurrected as valid later on. ExprEngine &Eng = BRC.getBugReporter().getEngine(); AnalyzerOptions &Options = Eng.getAnalysisManager().options; - if (Options.shouldPruneNullReturnPaths()) { - if (hasCounterSuppression(Options)) - Mode = MaybeSuppress; - else - BR.markInvalid(ReturnVisitor::getTag(), StackFrame); - } + if (EnableNullFPSuppression && hasCounterSuppression(Options)) + Mode = MaybeUnsuppress; if (RetE->getType()->isObjCObjectPointerType()) Out << "Returning nil"; @@ -267,21 +304,37 @@ public: Out << "Returning zero"; } - // FIXME: We should have a more generalized location printing mechanism. - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) - if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) - Out << " (loaded from '" << *DD << "')"; + if (LValue) { + if (const MemRegion *MR = LValue->getAsRegion()) { + if (MR->canPrintPretty()) { + Out << " (reference to '"; + MR->printPretty(Out); + Out << "')"; + } + } + } else { + // FIXME: We should have a more generalized location printing mechanism. + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) + Out << " (loaded from '" << *DD << "')"; + } PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame); return new PathDiagnosticEventPiece(L, Out.str()); } - PathDiagnosticPiece *visitNodeMaybeSuppress(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) { + PathDiagnosticPiece *visitNodeMaybeUnsuppress(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { +#ifndef NDEBUG + ExprEngine &Eng = BRC.getBugReporter().getEngine(); + AnalyzerOptions &Options = Eng.getAnalysisManager().options; + assert(hasCounterSuppression(Options)); +#endif + // Are we at the entry node for this call? - const CallEnter *CE = N->getLocationAs<CallEnter>(); + Optional<CallEnter> CE = N->getLocationAs<CallEnter>(); if (!CE) return 0; @@ -290,41 +343,36 @@ public: Mode = Satisfied; - ExprEngine &Eng = BRC.getBugReporter().getEngine(); - AnalyzerOptions &Options = Eng.getAnalysisManager().options; - if (Options.shouldAvoidSuppressingNullArgumentPaths()) { - // Don't automatically suppress a report if one of the arguments is - // known to be a null pointer. Instead, start tracking /that/ null - // value back to its origin. - ProgramStateManager &StateMgr = BRC.getStateManager(); - CallEventManager &CallMgr = StateMgr.getCallEventManager(); + // Don't automatically suppress a report if one of the arguments is + // known to be a null pointer. Instead, start tracking /that/ null + // value back to its origin. + ProgramStateManager &StateMgr = BRC.getStateManager(); + CallEventManager &CallMgr = StateMgr.getCallEventManager(); - ProgramStateRef State = N->getState(); - CallEventRef<> Call = CallMgr.getCaller(StackFrame, State); - for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) { - SVal ArgV = Call->getArgSVal(I); - if (!isa<Loc>(ArgV)) - continue; + ProgramStateRef State = N->getState(); + CallEventRef<> Call = CallMgr.getCaller(StackFrame, State); + for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) { + Optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>(); + if (!ArgV) + continue; - const Expr *ArgE = Call->getArgExpr(I); - if (!ArgE) - continue; + const Expr *ArgE = Call->getArgExpr(I); + if (!ArgE) + continue; - // Is it possible for this argument to be non-null? - if (State->assume(cast<Loc>(ArgV), true)) - continue; + // Is it possible for this argument to be non-null? + if (!State->isNull(*ArgV).isConstrainedTrue()) + continue; - if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true)) - return 0; + if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true, + EnableNullFPSuppression)) + BR.removeInvalidation(ReturnVisitor::getTag(), StackFrame); - // If we /can't/ track the null pointer, we should err on the side of - // false negatives, and continue towards marking this report invalid. - // (We will still look at the other arguments, though.) - } + // If we /can't/ track the null pointer, we should err on the side of + // false negatives, and continue towards marking this report invalid. + // (We will still look at the other arguments, though.) } - // There is no reason not to suppress this report; go ahead and do it. - BR.markInvalid(ReturnVisitor::getTag(), StackFrame); return 0; } @@ -335,14 +383,22 @@ public: switch (Mode) { case Initial: return visitNodeInitial(N, PrevN, BRC, BR); - case MaybeSuppress: - return visitNodeMaybeSuppress(N, PrevN, BRC, BR); + case MaybeUnsuppress: + return visitNodeMaybeUnsuppress(N, PrevN, BRC, BR); case Satisfied: return 0; } llvm_unreachable("Invalid visit mode!"); } + + PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR) { + if (EnableNullFPSuppression) + BR.markInvalid(ReturnVisitor::getTag(), StackFrame); + return 0; + } }; } // end anonymous namespace @@ -352,6 +408,7 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(&tag); ID.AddPointer(R); ID.Add(V); + ID.AddBoolean(EnableNullFPSuppression); } PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, @@ -359,7 +416,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, BugReport &BR) { - if (satisfied) + if (Satisfied) return NULL; const ExplodedNode *StoreSite = 0; @@ -368,7 +425,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // First see if we reached the declaration of the region. if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - if (const PostStmt *P = Pred->getLocationAs<PostStmt>()) { + if (Optional<PostStmt> P = Pred->getLocationAs<PostStmt>()) { if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) { if (DS->getSingleDecl() == VR->getDecl()) { StoreSite = Pred; @@ -378,19 +435,36 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } } - // Otherwise, check that Succ has this binding and Pred does not, i.e. this is - // where the binding first occurred. + // If this is a post initializer expression, initializing the region, we + // should track the initializer expression. + if (Optional<PostInitializer> PIP = Pred->getLocationAs<PostInitializer>()) { + const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue(); + if (FieldReg && FieldReg == R) { + StoreSite = Pred; + InitE = PIP->getInitializer()->getInit(); + } + } + + // Otherwise, see if this is the store site: + // (1) Succ has this binding and Pred does not, i.e. this is + // where the binding first occurred. + // (2) Succ has this binding and is a PostStore node for this region, i.e. + // the same binding was re-assigned here. if (!StoreSite) { if (Succ->getState()->getSVal(R) != V) return NULL; - if (Pred->getState()->getSVal(R) == V) - return NULL; + + if (Pred->getState()->getSVal(R) == V) { + Optional<PostStore> PS = Succ->getLocationAs<PostStore>(); + if (!PS || PS->getLocationValue() != R) + return NULL; + } StoreSite = Succ; // If this is an assignment expression, we can track the value // being assigned. - if (const PostStmt *P = Succ->getLocationAs<PostStmt>()) + if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) if (BO->isAssignmentOp()) InitE = BO->getRHS(); @@ -399,34 +473,41 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // FIXME: Handle CXXThisRegion as well. (This is not a priority because // 'this' should never be NULL, but this visitor isn't just for NULL and // UndefinedVal.) - if (const CallEnter *CE = Succ->getLocationAs<CallEnter>()) { - const VarRegion *VR = cast<VarRegion>(R); - const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); - - ProgramStateManager &StateMgr = BRC.getStateManager(); - CallEventManager &CallMgr = StateMgr.getCallEventManager(); + if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) { + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); + + ProgramStateManager &StateMgr = BRC.getStateManager(); + CallEventManager &CallMgr = StateMgr.getCallEventManager(); - CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(), - Succ->getState()); - InitE = Call->getArgExpr(Param->getFunctionScopeIndex()); - IsParam = true; + CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(), + Succ->getState()); + InitE = Call->getArgExpr(Param->getFunctionScopeIndex()); + IsParam = true; + } } + + // If this is a CXXTempObjectRegion, the Expr responsible for its creation + // is wrapped inside of it. + if (const CXXTempObjectRegion *TmpR = dyn_cast<CXXTempObjectRegion>(R)) + InitE = TmpR->getExpr(); } if (!StoreSite) return NULL; - satisfied = true; + Satisfied = true; // If we have an expression that provided the value, try to track where it // came from. if (InitE) { - if (V.isUndef() || isa<loc::ConcreteInt>(V)) { + if (V.isUndef() || V.getAs<loc::ConcreteInt>()) { if (!IsParam) InitE = InitE->IgnoreParenCasts(); - bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam); + bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam, + EnableNullFPSuppression); } else { ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(), - BR); + BR, EnableNullFPSuppression); } } @@ -437,73 +518,103 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); - if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) { - if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { + if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) { + const Stmt *S = PS->getStmt(); + const char *action = 0; + const DeclStmt *DS = dyn_cast<DeclStmt>(S); + const VarRegion *VR = dyn_cast<VarRegion>(R); - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << "Variable '" << *VR->getDecl() << "' "; + if (DS) { + action = "initialized to "; + } else if (isa<BlockExpr>(S)) { + action = "captured by block as "; + if (VR) { + // See if we can get the BlockVarRegion. + ProgramStateRef State = StoreSite->getState(); + SVal V = State->getSVal(S, PS->getLocationContext()); + if (const BlockDataRegion *BDR = + dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) { + if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) { + if (Optional<KnownSVal> KV = + State->getSVal(OriginalR).getAs<KnownSVal>()) + BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR, + EnableNullFPSuppression)); + } + } } - else - return NULL; + } + + if (action) { + if (!R) + return 0; + + os << '\''; + R->printPretty(os); + os << "' "; - if (isa<loc::ConcreteInt>(V)) { + if (V.getAs<loc::ConcreteInt>()) { bool b = false; if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { - os << "initialized to nil"; + os << action << "nil"; b = true; } } } if (!b) - os << "initialized to a null pointer value"; - } - else if (isa<nonloc::ConcreteInt>(V)) { - os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue(); + os << action << "a null pointer value"; + } else if (Optional<nonloc::ConcreteInt> CVal = + V.getAs<nonloc::ConcreteInt>()) { + os << action << CVal->getValue(); } - else if (V.isUndef()) { - if (isa<VarRegion>(R)) { - const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); - if (VD->getInit()) - os << "initialized to a garbage value"; - else - os << "declared without an initial value"; + else if (DS) { + if (V.isUndef()) { + if (isa<VarRegion>(R)) { + const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); + if (VD->getInit()) + os << "initialized to a garbage value"; + else + os << "declared without an initial value"; + } + } + else { + os << "initialized here"; } - } - else { - os << "initialized here"; } } - } else if (isa<CallEnter>(StoreSite->getLocation())) { - const ParmVarDecl *Param = cast<ParmVarDecl>(cast<VarRegion>(R)->getDecl()); + } else if (StoreSite->getLocation().getAs<CallEnter>()) { + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); - os << "Passing "; + os << "Passing "; - if (isa<loc::ConcreteInt>(V)) { - if (Param->getType()->isObjCObjectPointerType()) - os << "nil object reference"; - else - os << "null pointer value"; - } else if (V.isUndef()) { - os << "uninitialized value"; - } else if (isa<nonloc::ConcreteInt>(V)) { - os << "the value " << cast<nonloc::ConcreteInt>(V).getValue(); - } else { - os << "value"; - } + if (V.getAs<loc::ConcreteInt>()) { + if (Param->getType()->isObjCObjectPointerType()) + os << "nil object reference"; + else + os << "null pointer value"; + } else if (V.isUndef()) { + os << "uninitialized value"; + } else if (Optional<nonloc::ConcreteInt> CI = + V.getAs<nonloc::ConcreteInt>()) { + os << "the value " << CI->getValue(); + } else { + os << "value"; + } - // Printed parameter indexes are 1-based, not 0-based. - unsigned Idx = Param->getFunctionScopeIndex() + 1; - os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; + // Printed parameter indexes are 1-based, not 0-based. + unsigned Idx = Param->getFunctionScopeIndex() + 1; + os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; - R->printPretty(os); - os << '\''; + R->printPretty(os); + os << '\''; + } } if (os.str().empty()) { - if (isa<loc::ConcreteInt>(V)) { + if (V.getAs<loc::ConcreteInt>()) { bool b = false; if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { @@ -519,10 +630,9 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } else if (V.isUndef()) { os << "Uninitialized value stored to "; - } - else if (isa<nonloc::ConcreteInt>(V)) { - os << "The value " << cast<nonloc::ConcreteInt>(V).getValue() - << " is assigned to "; + } else if (Optional<nonloc::ConcreteInt> CV = + V.getAs<nonloc::ConcreteInt>()) { + os << "The value " << CV->getValue() << " is assigned to "; } else os << "Value assigned to "; @@ -535,7 +645,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // Construct a new PathDiagnosticPiece. ProgramPoint P = StoreSite->getLocation(); PathDiagnosticLocation L; - if (isa<CallEnter>(P)) + if (P.getAs<CallEnter>() && InitE) L = PathDiagnosticLocation(InitE, BRC.getSourceManager(), P.getLocationContext()); else @@ -558,32 +668,38 @@ const char *TrackConstraintBRVisitor::getTag() { return "TrackConstraintBRVisitor"; } +bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const { + if (IsZeroCheck) + return N->getState()->isNull(Constraint).isUnderconstrained(); + return N->getState()->assume(Constraint, !Assumption); +} + PathDiagnosticPiece * TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { - if (isSatisfied) + if (IsSatisfied) return NULL; // Check if in the previous state it was feasible for this constraint // to *not* be true. - if (PrevN->getState()->assume(Constraint, !Assumption)) { + if (isUnderconstrained(PrevN)) { - isSatisfied = true; + IsSatisfied = true; // As a sanity check, make sure that the negation of the constraint // was infeasible in the current state. If it is feasible, we somehow // missed the transition point. - if (N->getState()->assume(Constraint, !Assumption)) + if (isUnderconstrained(N)) return NULL; // We found the transition point for the constraint. We now need to // pretty-print the constraint. (work-in-progress) - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + SmallString<64> sbuf; + llvm::raw_svector_ostream os(sbuf); - if (isa<Loc>(Constraint)) { + if (Constraint.getAs<Loc>()) { os << "Assuming pointer value is "; os << (Assumption ? "non-null" : "null"); } @@ -606,25 +722,151 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, return NULL; } -bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, - BugReport &report, bool IsArg) { +SuppressInlineDefensiveChecksVisitor:: +SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N) + : V(Value), IsSatisfied(false), IsTrackingTurnedOn(false) { + + // Check if the visitor is disabled. + SubEngine *Eng = N->getState()->getStateManager().getOwningEngine(); + assert(Eng && "Cannot file a bug report without an owning engine"); + AnalyzerOptions &Options = Eng->getAnalysisManager().options; + if (!Options.shouldSuppressInlinedDefensiveChecks()) + IsSatisfied = true; + + assert(N->getState()->isNull(V).isConstrainedTrue() && + "The visitor only tracks the cases where V is constrained to 0"); +} + +void SuppressInlineDefensiveChecksVisitor::Profile(FoldingSetNodeID &ID) const { + static int id = 0; + ID.AddPointer(&id); + ID.Add(V); +} + +const char *SuppressInlineDefensiveChecksVisitor::getTag() { + return "IDCVisitor"; +} + +PathDiagnosticPiece * +SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) { + if (IsSatisfied) + return 0; + + // Start tracking after we see the first state in which the value is null. + if (!IsTrackingTurnedOn) + if (Succ->getState()->isNull(V).isConstrainedTrue()) + IsTrackingTurnedOn = true; + if (!IsTrackingTurnedOn) + return 0; + + // Check if in the previous state it was feasible for this value + // to *not* be null. + if (!Pred->getState()->isNull(V).isConstrainedTrue()) { + IsSatisfied = true; + + assert(Succ->getState()->isNull(V).isConstrainedTrue()); + + // Check if this is inlined defensive checks. + const LocationContext *CurLC =Succ->getLocationContext(); + const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext(); + if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) + BR.markInvalid("Suppress IDC", CurLC); + } + return 0; +} + +static const MemRegion *getLocationRegionIfReference(const Expr *E, + const ExplodedNode *N) { + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + if (!VD->getType()->isReferenceType()) + return 0; + ProgramStateManager &StateMgr = N->getState()->getStateManager(); + MemRegionManager &MRMgr = StateMgr.getRegionManager(); + return MRMgr.getVarRegion(VD, N->getLocationContext()); + } + } + + // FIXME: This does not handle other kinds of null references, + // for example, references from FieldRegions: + // struct Wrapper { int &ref; }; + // Wrapper w = { *(int *)0 }; + // w.ref = 1; + + return 0; +} + +static const Expr *peelOffOuterExpr(const Expr *Ex, + const ExplodedNode *N) { + Ex = Ex->IgnoreParenCasts(); + if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Ex)) + return peelOffOuterExpr(EWC->getSubExpr(), N); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Ex)) + return peelOffOuterExpr(OVE->getSourceExpr(), N); + + // Peel off the ternary operator. + if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) { + // Find a node where the branching occured and find out which branch + // we took (true/false) by looking at the ExplodedGraph. + const ExplodedNode *NI = N; + do { + ProgramPoint ProgPoint = NI->getLocation(); + if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) { + const CFGBlock *srcBlk = BE->getSrc(); + if (const Stmt *term = srcBlk->getTerminator()) { + if (term == CO) { + bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst()); + if (TookTrueBranch) + return peelOffOuterExpr(CO->getTrueExpr(), N); + else + return peelOffOuterExpr(CO->getFalseExpr(), N); + } + } + } + NI = NI->getFirstPred(); + } while (NI); + } + return Ex; +} + +bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, + const Stmt *S, + BugReport &report, bool IsArg, + bool EnableNullFPSuppression) { if (!S || !N) return false; - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) - S = OVE->getSourceExpr(); + if (const Expr *Ex = dyn_cast<Expr>(S)) { + Ex = Ex->IgnoreParenCasts(); + const Expr *PeeledEx = peelOffOuterExpr(Ex, N); + if (Ex != PeeledEx) + S = PeeledEx; + } + + const Expr *Inner = 0; + if (const Expr *Ex = dyn_cast<Expr>(S)) { + Ex = Ex->IgnoreParenCasts(); + if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)) + Inner = Ex; + } if (IsArg) { - assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call"); + assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call"); } else { // Walk through nodes until we get one that matches the statement exactly. + // Alternately, if we hit a known lvalue for the statement, we know we've + // gone too far (though we can likely track the lvalue better anyway). do { const ProgramPoint &pp = N->getLocation(); - if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { - if (ps->getStmt() == S) + if (Optional<StmtPoint> ps = pp.getAs<StmtPoint>()) { + if (ps->getStmt() == S || ps->getStmt() == Inner) break; - } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) { - if (CEE->getCalleeContext()->getCallSite() == S) + } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) { + if (CEE->getCalleeContext()->getCallSite() == S || + CEE->getCalleeContext()->getCallSite() == Inner) break; } N = N->getFirstPred(); @@ -636,129 +878,167 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, ProgramStateRef state = N->getState(); - // See if the expression we're interested refers to a variable. + // The message send could be nil due to the receiver being nil. + // At this point in the path, the receiver should be live since we are at the + // message send expr. If it is nil, start tracking it. + if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(S, N)) + trackNullOrUndefValue(N, Receiver, report, IsArg, EnableNullFPSuppression); + + + // See if the expression we're interested refers to a variable. // If so, we can track both its contents and constraints on its value. - if (const Expr *Ex = dyn_cast<Expr>(S)) { - // Strip off parens and casts. Note that this will never have issues with - // C++ user-defined implicit conversions, because those have a constructor - // or function call inside. - Ex = Ex->IgnoreParenCasts(); - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { - // FIXME: Right now we only track VarDecls because it's non-trivial to - // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812> - if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - ProgramStateManager &StateMgr = state->getStateManager(); - MemRegionManager &MRMgr = StateMgr.getRegionManager(); - const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext()); + if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) { + const MemRegion *R = 0; - // Mark both the variable region and its contents as interesting. - SVal V = state->getRawSVal(loc::MemRegionVal(R)); + // Find the ExplodedNode where the lvalue (the value of 'Ex') + // was computed. We need this for getting the location value. + const ExplodedNode *LVNode = N; + while (LVNode) { + if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) { + if (P->getStmt() == Inner) + break; + } + LVNode = LVNode->getFirstPred(); + } + assert(LVNode && "Unable to find the lvalue node."); + ProgramStateRef LVState = LVNode->getState(); + SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext()); + + if (LVState->isNull(LVal).isConstrainedTrue()) { + // In case of C++ references, we want to differentiate between a null + // reference and reference to null pointer. + // If the LVal is null, check if we are dealing with null reference. + // For those, we want to track the location of the reference. + if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) + R = RR; + } else { + R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion(); - // If the value matches the default for the variable region, that - // might mean that it's been cleared out of the state. Fall back to - // the full argument expression (with casts and such intact). - if (IsArg) { - bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant(); - if (!UseArgValue) { - const SymbolRegionValue *SRV = - dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol()); - if (SRV) - UseArgValue = (SRV->getRegion() == R); - } - if (UseArgValue) - V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); - } + // If this is a C++ reference to a null pointer, we are tracking the + // pointer. In additon, we should find the store at which the reference + // got initialized. + if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) { + if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>()) + report.addVisitor(new FindLastStoreBRVisitor(*KV, RR, + EnableNullFPSuppression)); + } + } - report.markInteresting(R); - report.markInteresting(V); - report.addVisitor(new UndefOrNullArgVisitor(R)); + if (R) { + // Mark both the variable region and its contents as interesting. + SVal V = state->getRawSVal(loc::MemRegionVal(R)); - // If the contents are symbolic, find out when they became null. - if (V.getAsLocSymbol()) { - BugReporterVisitor *ConstraintTracker - = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false); - report.addVisitor(ConstraintTracker); + // If the value matches the default for the variable region, that + // might mean that it's been cleared out of the state. Fall back to + // the full argument expression (with casts and such intact). + if (IsArg) { + bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant(); + if (!UseArgValue) { + const SymbolRegionValue *SRV = + dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol()); + if (SRV) + UseArgValue = (SRV->getRegion() == R); } + if (UseArgValue) + V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); + } + + report.markInteresting(R); + report.markInteresting(V); + report.addVisitor(new UndefOrNullArgVisitor(R)); + + if (isa<SymbolicRegion>(R)) { + TrackConstraintBRVisitor *VI = + new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); + report.addVisitor(VI); + } + + // If the contents are symbolic, find out when they became null. + if (V.getAsLocSymbol()) { + BugReporterVisitor *ConstraintTracker = + new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false); + report.addVisitor(ConstraintTracker); - report.addVisitor(new FindLastStoreBRVisitor(V, R)); - return true; + // Add visitor, which will suppress inline defensive checks. + if (N->getState()->isNull(V).isConstrainedTrue() && + EnableNullFPSuppression) { + BugReporterVisitor *IDCSuppressor = + new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(), + N); + report.addVisitor(IDCSuppressor); + } } + + if (Optional<KnownSVal> KV = V.getAs<KnownSVal>()) + report.addVisitor(new FindLastStoreBRVisitor(*KV, R, + EnableNullFPSuppression)); + return true; } } - // If the expression does NOT refer to a variable, we can still track - // constraints on its contents. + // If the expression is not an "lvalue expression", we can still + // track the constraints on its contents. SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); + // If the value came from an inlined function call, we should at least make + // sure that function isn't pruned in our output. + if (const Expr *E = dyn_cast<Expr>(S)) + S = E->IgnoreParenCasts(); + + ReturnVisitor::addVisitorIfNecessary(N, S, report, EnableNullFPSuppression); + // Uncomment this to find cases where we aren't properly getting the // base value that was dereferenced. // assert(!V.isUnknownOrUndef()); - // Is it a symbolic value? - if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { + if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) { // At this point we are dealing with the region's LValue. // However, if the rvalue is a symbolic region, we should track it as well. SVal RVal = state->getSVal(L->getRegion()); const MemRegion *RegionRVal = RVal.getAsRegion(); report.addVisitor(new UndefOrNullArgVisitor(L->getRegion())); - if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) { report.markInteresting(RegionRVal); report.addVisitor(new TrackConstraintBRVisitor( loc::MemRegionVal(RegionRVal), false)); } - } else { - // Otherwise, if the value came from an inlined function call, - // we should at least make sure that function isn't pruned in our output. - if (const Expr *E = dyn_cast<Expr>(S)) - S = E->IgnoreParenCasts(); - ReturnVisitor::addVisitorIfNecessary(N, S, report); } return true; } -BugReporterVisitor * -FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N, - const MemRegion *R) { - assert(R && "The memory region is null."); - - ProgramStateRef state = N->getState(); - SVal V = state->getSVal(R); - if (V.isUnknown()) +const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S, + const ExplodedNode *N) { + const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S); + if (!ME) return 0; - - return new FindLastStoreBRVisitor(V, R); + if (const Expr *Receiver = ME->getInstanceReceiver()) { + ProgramStateRef state = N->getState(); + SVal V = state->getSVal(Receiver, N->getLocationContext()); + if (state->isNull(V).isConstrainedTrue()) + return Receiver; + } + return 0; } - PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) { - const PostStmt *P = N->getLocationAs<PostStmt>(); + Optional<PreStmt> P = N->getLocationAs<PreStmt>(); if (!P) return 0; - const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); - if (!ME) - return 0; - const Expr *Receiver = ME->getInstanceReceiver(); + + const Expr *Receiver = getNilReceiver(P->getStmt(), N); if (!Receiver) return 0; - ProgramStateRef state = N->getState(); - const SVal &V = state->getSVal(Receiver, N->getLocationContext()); - const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); - if (!DV) - return 0; - state = state->assume(*DV, true); - if (state) - return 0; // The receiver was nil, and hence the method was skipped. // Register a BugReporterVisitor to issue a message telling us how // the receiver was null. - bugreporter::trackNullOrUndefValue(N, Receiver, BR); + bugreporter::trackNullOrUndefValue(N, Receiver, BR, /*IsArg*/ false, + /*EnableNullFPSuppression*/ false); // Issue a message saying that the method was skipped. PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), N->getLocationContext()); @@ -768,7 +1048,8 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, // Registers every VarDecl inside a Stmt with a last store visitor. void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, - const Stmt *S) { + const Stmt *S, + bool EnableNullFPSuppression) { const ExplodedNode *N = BR.getErrorNode(); std::deque<const Stmt *> WorkList; WorkList.push_back(S); @@ -788,9 +1069,10 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, // What did we load? SVal V = state->getSVal(S, N->getLocationContext()); - if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) { + if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) { // Register a new visitor with the BugReport. - BR.addVisitor(new FindLastStoreBRVisitor(V, R)); + BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R, + EnableNullFPSuppression)); } } } @@ -842,14 +1124,14 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, // If an assumption was made on a branch, it should be caught // here by looking at the state transition. - if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) { + if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) { const CFGBlock *srcBlk = BE->getSrc(); if (const Stmt *term = srcBlk->getTerminator()) return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); return 0; } - if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) { + if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) { // FIXME: Assuming that BugReporter is a GRBugReporter is a layering // violation. const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = @@ -929,11 +1211,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, } } -bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out, +bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out, BugReporterContext &BRC, BugReport &report, const ExplodedNode *N, - llvm::Optional<bool> &prunable) { + Optional<bool> &prunable) { const Expr *OriginalExpr = Ex; Ex = Ex->IgnoreParenCasts(); @@ -992,7 +1274,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const ExplodedNode *N) { bool shouldInvert = false; - llvm::Optional<bool> shouldPrune; + Optional<bool> shouldPrune; SmallString<128> LhsString, RhsString; { @@ -1161,6 +1443,58 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, return event; } + +// FIXME: Copied from ExprEngineCallAndReturn.cpp. +static bool isInStdNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext(); + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); + if (!ND) + return false; + + while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent())) + ND = Parent; + + return ND->getName() == "std"; +} + + +PathDiagnosticPiece * +LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR) { + // Here we suppress false positives coming from system headers. This list is + // based on known issues. + + // Skip reports within the 'std' namespace. Although these can sometimes be + // the user's fault, we currently don't report them very well, and + // Note that this will not help for any other data structure libraries, like + // TR1, Boost, or llvm/ADT. + ExprEngine &Eng = BRC.getBugReporter().getEngine(); + AnalyzerOptions &Options = Eng.getAnalysisManager().options; + if (Options.shouldSuppressFromCXXStandardLibrary()) { + const LocationContext *LCtx = N->getLocationContext(); + if (isInStdNamespace(LCtx->getDecl())) { + BR.markInvalid(getTag(), 0); + return 0; + } + } + + // Skip reports within the sys/queue.h macros as we do not have the ability to + // reason about data structure shapes. + SourceManager &SM = BRC.getSourceManager(); + FullSourceLoc Loc = BR.getLocation(SM).asLocation(); + while (Loc.isMacroID()) { + if (SM.isInSystemMacro(Loc) && + (SM.getFilename(SM.getSpellingLoc(Loc)).endswith("sys/queue.h"))) { + BR.markInvalid(getTag(), 0); + return 0; + } + Loc = Loc.getSpellingLoc(); + } + + return 0; +} + PathDiagnosticPiece * UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, @@ -1171,7 +1505,7 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, ProgramPoint ProgLoc = N->getLocation(); // We are only interested in visiting CallEnter nodes. - CallEnter *CEnter = dyn_cast<CallEnter>(&ProgLoc); + Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>(); if (!CEnter) return 0; |
