SVal V;
bool Satisfied;
-public:
- /// \brief Convenience method to create a visitor given only the MemRegion.
- /// Returns NULL if the visitor cannot be created. For example, when the
- /// corresponding value is unknown.
- static BugReporterVisitor *createVisitorObject(const ExplodedNode *N,
- const MemRegion *R);
+ /// If the visitor is tracking the value directly responsible for the
+ /// bug, we are going to employ false positive suppression.
+ bool EnableNullFPSuppression;
+public:
/// Creates a visitor for every VarDecl inside a Stmt and registers it with
/// the BugReport.
- static void registerStatementVarDecls(BugReport &BR, const Stmt *S);
+ static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
+ bool EnableNullFPSuppression);
- FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R)
+ FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
+ bool InEnableNullFPSuppression)
: R(R),
V(V),
- Satisfied(false) {}
+ Satisfied(false),
+ EnableNullFPSuppression(InEnableNullFPSuppression) {}
void Profile(llvm::FoldingSetNodeID &ID) const;
/// \brief Prints path notes when a message is sent to a nil receiver.
class NilReceiverBRVisitor
: public BugReporterVisitorImpl<NilReceiverBRVisitor> {
+
+ /// \brief The reciever to track. If null, all receivers should be tracked.
+ const Expr *TrackedReceiver;
+
+ /// If the visitor is tracking the value directly responsible for the
+ /// bug, we are going to employ false positive suppression.
+ bool EnableNullFPSuppression;
+
public:
+ NilReceiverBRVisitor(const Expr *InTrackedReceiver = 0,
+ bool InEnableNullFPSuppression = false):
+ TrackedReceiver(InTrackedReceiver),
+ EnableNullFPSuppression(InEnableNullFPSuppression) {}
+
void Profile(llvm::FoldingSetNodeID &ID) const {
static int x = 0;
ID.AddPointer(&x);
+ ID.AddPointer(TrackedReceiver);
+ ID.AddBoolean(EnableNullFPSuppression);
}
PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR);
+
+ static const Expr *getReceiver(const Stmt *S);
};
/// Visitor that tries to report interesting diagnostics from conditions.
/// \param IsArg Whether the statement is an argument to an inlined function.
/// If this is the case, \p N \em must be the CallEnter node for
/// the function.
+/// \param EnableNullFPSuppression Whether we should employ false positive
+/// suppression (inlined defensive checks, returned null).
///
/// \return Whether or not the function was able to add visitors for this
/// statement. Note that returning \c true does not actually imply
/// that any visitors were added.
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
- bool IsArg = false);
+ bool IsArg = false,
+ bool EnableNullFPSuppression = true);
const Expr *getDerefExpr(const Stmt *S);
const Stmt *GetDenomExpr(const ExplodedNode *N);
MaybeUnsuppress,
Satisfied
} Mode;
- bool InitiallySuppressed;
+
+ bool EnableNullFPSuppression;
public:
ReturnVisitor(const StackFrameContext *Frame, bool Suppressed)
- : StackFrame(Frame), Mode(Initial), InitiallySuppressed(Suppressed) {}
+ : StackFrame(Frame), Mode(Initial), EnableNullFPSuppression(Suppressed) {}
static void *getTag() {
static int Tag = 0;
virtual void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(ReturnVisitor::getTag());
ID.AddPointer(StackFrame);
- ID.AddBoolean(InitiallySuppressed);
+ ID.AddBoolean(EnableNullFPSuppression);
}
/// Adds a ReturnVisitor if the given statement represents a call that was
/// 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;
assert(Eng && "Cannot file a bug report without an owning engine");
AnalyzerOptions &Options = Eng->getAnalysisManager().options;
- bool InitiallySuppressed = false;
- if (Options.shouldSuppressNullReturnPaths())
+ bool EnableNullFPSuppression = false;
+ if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths())
if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
- InitiallySuppressed = State->isNull(*RetLoc).isConstrainedTrue();
+ EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
BR.markInteresting(CalleeContext);
- BR.addVisitor(new ReturnVisitor(CalleeContext, InitiallySuppressed));
+ BR.addVisitor(new ReturnVisitor(CalleeContext, EnableNullFPSuppression));
}
/// Returns true if any counter-suppression heuristics are enabled for
// make sure to track it into any further inner functions.
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;
// the report is resurrected as valid later on.
ExprEngine &Eng = BRC.getBugReporter().getEngine();
AnalyzerOptions &Options = Eng.getAnalysisManager().options;
- if (InitiallySuppressed && hasCounterSuppression(Options))
+ if (EnableNullFPSuppression && hasCounterSuppression(Options))
Mode = MaybeUnsuppress;
if (RetE->getType()->isObjCObjectPointerType())
if (!State->isNull(*ArgV).isConstrainedTrue())
continue;
- if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true))
+ 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
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR) {
- if (InitiallySuppressed)
+ if (EnableNullFPSuppression)
BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
return 0;
}
ID.AddPointer(&tag);
ID.AddPointer(R);
ID.Add(V);
+ ID.AddBoolean(EnableNullFPSuppression);
}
PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
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);
}
}
if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
if (Optional<KnownSVal> KV =
State->getSVal(OriginalR).getAs<KnownSVal>())
- BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR));
+ BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR,
+ EnableNullFPSuppression));
}
}
}
bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
const Stmt *S,
- BugReport &report, bool IsArg) {
+ BugReport &report, bool IsArg,
+ bool EnableNullFPSuppression) {
if (!S || !N)
return false;
S = Ex;
}
+ // The message send could be null if the receiver is null.
+ if (const Expr *Receiver = NilReceiverBRVisitor::getReceiver(S)) {
+ report.addVisitor(new NilReceiverBRVisitor(Receiver,
+ EnableNullFPSuppression));
+ }
+
const Expr *Inner = 0;
if (const Expr *Ex = dyn_cast<Expr>(S)) {
Ex = Ex->IgnoreParenCasts();
// got initialized.
if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) {
if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>())
- report.addVisitor(new FindLastStoreBRVisitor(*KV, RR));
+ report.addVisitor(new FindLastStoreBRVisitor(*KV, RR,
+ EnableNullFPSuppression));
}
}
report.addVisitor(ConstraintTracker);
// Add visitor, which will suppress inline defensive checks.
- if (N->getState()->isNull(V).isConstrainedTrue()) {
+ if (N->getState()->isNull(V).isConstrainedTrue() &&
+ EnableNullFPSuppression) {
BugReporterVisitor *IDCSuppressor =
new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
N);
}
if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
- report.addVisitor(new FindLastStoreBRVisitor(*KV, R));
+ report.addVisitor(new FindLastStoreBRVisitor(*KV, R,
+ EnableNullFPSuppression));
return true;
}
}
// 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);
+
+ ReturnVisitor::addVisitorIfNecessary(N, S, report, EnableNullFPSuppression);
// Uncomment this to find cases where we aren't properly getting the
// base value that was dereferenced.
return true;
}
-BugReporterVisitor *
-FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N,
- const MemRegion *R) {
- assert(R && "The memory region is null.");
-
- ProgramStateRef state = N->getState();
- if (Optional<KnownSVal> KV = state->getSVal(R).getAs<KnownSVal>())
- return new FindLastStoreBRVisitor(*KV, R);
- return 0;
+const Expr *NilReceiverBRVisitor::getReceiver(const Stmt *S) {
+ const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
+ if (!ME)
+ return 0;
+ return ME->getInstanceReceiver();
}
PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
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 = getReceiver(P->getStmt());
if (!Receiver)
return 0;
+ // Are we tracking a different reciever?
+ if (TrackedReceiver && TrackedReceiver != Receiver)
+ return 0;
+
ProgramStateRef state = N->getState();
SVal V = state->getSVal(Receiver, N->getLocationContext());
if (!state->isNull(V).isConstrainedTrue())
// 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);
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
// 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);
if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
// Register a new visitor with the BugReport.
- BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R));
+ BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R,
+ EnableNullFPSuppression));
}
}
}