]> granicus.if.org Git - clang/commitdiff
[analyzer] trackNullOrUndefValue: track last store to non-variables.
authorArtem Dergachev <artem.dergachev@gmail.com>
Wed, 20 Dec 2017 00:47:17 +0000 (00:47 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Wed, 20 Dec 2017 00:47:17 +0000 (00:47 +0000)
When reporting certain kinds of analyzer warnings, we use the
bugreporter::trackNullOrUndefValue mechanism, which is part of public checker
API, to understand where a zero, null-pointer, or garbage value came from,
which would highlight important events with respect to that value in the
diagnostic path notes, and help us suppress various false positives that result
from values appearing from particular sources.

Previously, we've lost track of the value when it was written into a memory
region that is not a plain variable. Now try to resume tracking in this
situation by finding where the last write to this region has occured.

Differential revision: https://reviews.llvm.org/D41253

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@321130 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
test/Analysis/inlining/inline-defensive-checks.c
test/Analysis/nullptr.cpp

index 7304d789431eee26274f7b56455ee2c351ba01ee..993c5857088f53124a7a40be0fef57a1fd2e921e 100644 (file)
@@ -1142,9 +1142,12 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
     else
       RVal = state->getSVal(L->getRegion());
 
-    const MemRegion *RegionRVal = RVal.getAsRegion();
     report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(L->getRegion()));
+    if (Optional<KnownSVal> KV = RVal.getAs<KnownSVal>())
+      report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
+          *KV, L->getRegion(), EnableNullFPSuppression));
 
+    const MemRegion *RegionRVal = RVal.getAsRegion();
     if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
       report.markInteresting(RegionRVal);
       report.addVisitor(llvm::make_unique<TrackConstraintBRVisitor>(
index 9f211b502bc0e58ed710f8f0cb75d1820c0a9db3..7440c77736e8fb719123970c18d35512dd6a2541 100644 (file)
@@ -190,3 +190,21 @@ void idcTrackZeroValueThroughUnaryPointerOperatorsWithArrayField(struct S2 *s) {
   idc(s);
   *(&(s->a[0])) = 7; // no-warning
 }
+
+void idcTrackConstraintThroughSymbolicRegion(int **x) {
+  idc(*x);
+  // FIXME: Should not warn.
+  **x = 7; // expected-warning{{Dereference of null pointer}}
+}
+
+int *idcPlainNull(int coin) {
+  if (coin)
+    return 0;
+  static int X;
+  return &X;
+}
+
+void idcTrackZeroValueThroughSymbolicRegion(int coin, int **x) {
+  *x = idcPlainNull(coin);
+  **x = 7; // no-warning
+}
index b3e61c9defb99c1e2ad5cebf42671702ed1b9cd8..38e099b7fbdff21921e27f36db0a44bcc107993e 100644 (file)
@@ -142,8 +142,9 @@ void shouldNotCrash() {
                       // expected-note@-1{{Passing null pointer value via 1st parameter 'x'}}
   if (getSymbol()) {  // expected-note  {{Assuming the condition is true}}
                       // expected-note@-1{{Taking true branch}}
-    X *x = Type().x; // expected-note{{'x' initialized to a null pointer value}}
-    x->f(); // expected-warning{{Called C++ object pointer is null}}
+    X *xx = Type().x; // expected-note   {{Null pointer value stored to field 'x'}}
+                      // expected-note@-1{{'xx' initialized to a null pointer value}}
+    xx->f(); // expected-warning{{Called C++ object pointer is null}}
             // expected-note@-1{{Called C++ object pointer is null}}
   }
 }