aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2013-03-09 03:23:19 +0000
committerAnna Zaks <ganna@apple.com>2013-03-09 03:23:19 +0000
commit0415998dd77986630efe8f1aed633519cc41e1f3 (patch)
tree8d6dc33ccbeb6581c17673eda42fd027fc503db8
parent80412c4e28c8247ad9c8d30d04c94938f01b21fb (diff)
[analyzer] Make Suppress IDC checker aware that it might not start from the same node it was registered at
The visitor used to assume that the value it’s tracking is null in the first node it examines. This is not true. If we are registering the Suppress Inlined Defensive checks visitor while traversing in another visitor (such as FindlastStoreVisitor). When we restart with the IDC visitor, the invariance of the visitor does not hold since the symbol we are tracking no longer exists at that point. I had to pass the ErrorNode when creating the IDC visitor, because, in some cases, node N is neither the error node nor will be visible along the path (we had not finalized the path at that point and are dealing with ExplodedGraph.) We should revisit the other visitors which might not be aware that they might get nodes, which are later in path than the trigger point. This suppresses a number of inline defensive checks in JavaScriptCore. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176756 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h25
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp42
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.cpp32
3 files changed, 80 insertions, 19 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index c1b5594209..17c1009853 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -55,8 +55,8 @@ public:
///
/// The last parameter can be used to register a new visitor with the given
/// BugReport while processing a node.
- virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
BugReporterContext &BRC,
BugReport &BR) = 0;
@@ -283,13 +283,20 @@ public:
class SuppressInlineDefensiveChecksVisitor
: public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor>
{
- // The symbolic value for which we are tracking constraints.
- // This value is constrained to null in the end of path.
+ /// The symbolic value for which we are tracking constraints.
+ /// This value is constrained to null in the end of path.
DefinedSVal V;
- // Track if we found the node where the constraint was first added.
+ /// Track if we found the node where the constraint was first added.
bool IsSatisfied;
+ /// \brief The node from which we should start tracking the value.
+ /// Note: Since the visitors can be registered on nodes previous to the last
+ /// node in the BugReport, but the path traversal always starts with the last
+ /// node, the visitor invariant (that we start with a node in which V is null)
+ /// might not hold when node visitation starts.
+ const ExplodedNode *StartN;
+
public:
SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
@@ -299,8 +306,12 @@ public:
/// to make all PathDiagnosticPieces created by this visitor.
static const char *getTag();
- PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
+ PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
BugReporterContext &BRC,
BugReport &BR);
};
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 4b6dd09021..88e4ba5876 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -695,7 +695,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
SuppressInlineDefensiveChecksVisitor::
SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
- : V(Value), IsSatisfied(false) {
+ : V(Value), IsSatisfied(false), StartN(N) {
assert(N->getState()->isNull(V).isConstrainedTrue() &&
"The visitor only tracks the cases where V is constrained to 0");
@@ -704,6 +704,7 @@ SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
void SuppressInlineDefensiveChecksVisitor::Profile(FoldingSetNodeID &ID) const {
static int id = 0;
ID.AddPointer(&id);
+ ID.AddPointer(StartN);
ID.Add(V);
}
@@ -712,13 +713,28 @@ const char *SuppressInlineDefensiveChecksVisitor::getTag() {
}
PathDiagnosticPiece *
-SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
+SuppressInlineDefensiveChecksVisitor::getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) {
+ if (StartN == BR.getErrorNode())
+ StartN = 0;
+ return 0;
+}
+
+PathDiagnosticPiece *
+SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
BugReporterContext &BRC,
BugReport &BR) {
if (IsSatisfied)
return 0;
+ // Start tracking after we see node StartN.
+ if (StartN == Succ)
+ StartN = 0;
+ if (StartN)
+ return 0;
+
AnalyzerOptions &Options =
BRC.getBugReporter().getEngine().getAnalysisManager().options;
if (!Options.shouldSuppressInlinedDefensiveChecks())
@@ -726,14 +742,13 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *N,
// Check if in the previous state it was feasible for this value
// to *not* be null.
- if (PrevN->getState()->assume(V, true)) {
+ if (Pred->getState()->assume(V, true)) {
IsSatisfied = true;
- // TODO: Investigate if missing the transition point, where V
- // is non-null in N could lead to false negatives.
+ assert(!Succ->getState()->assume(V, true));
- // Check if this is inline defensive checks.
- const LocationContext *CurLC = N->getLocationContext();
+ // 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);
@@ -741,14 +756,17 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *N,
return 0;
}
-bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
+bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode,
+ const Stmt *S,
BugReport &report, bool IsArg) {
- if (!S || !N)
+ if (!S || !ErrorNode)
return false;
if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
S = OVE->getSourceExpr();
+ const ExplodedNode *N = ErrorNode;
+
const Expr *LValue = 0;
if (const Expr *Ex = dyn_cast<Expr>(S)) {
Ex = Ex->IgnoreParenCasts();
@@ -850,10 +868,10 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
report.addVisitor(ConstraintTracker);
// Add visitor, which will suppress inline defensive checks.
- if (N->getState()->isNull(V).isConstrainedTrue()) {
+ if (ErrorNode->getState()->isNull(V).isConstrainedTrue()) {
BugReporterVisitor *IDCSuppressor =
new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
- N);
+ ErrorNode);
report.addVisitor(IDCSuppressor);
}
}
diff --git a/test/Analysis/inlining/inline-defensive-checks.cpp b/test/Analysis/inlining/inline-defensive-checks.cpp
new file mode 100644
index 0000000000..c77961d03c
--- /dev/null
+++ b/test/Analysis/inlining/inline-defensive-checks.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// expected-no-diagnostics
+
+class ButterFly {
+private:
+ ButterFly() { }
+public:
+ int triggerderef() {
+ return 0;
+ }
+};
+ButterFly *getInP();
+class X{
+ ButterFly *p;
+ void setP(ButterFly *inP) {
+ if(inP)
+ ;
+ p = inP;
+ };
+ void subtest1() {
+ ButterFly *inP = getInP();
+ setP(inP);
+ }
+ int subtest2() {
+ int c = p->triggerderef(); // no-warning
+ return c;
+ }
+ int test() {
+ subtest1();
+ return subtest2();
+ }
+}; \ No newline at end of file