r246182 - [Static Analyzer] Make NonNullParamChecker emit implicit null dereference events.

Gabor Horvath via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 27 11:49:07 PDT 2015


Author: xazax
Date: Thu Aug 27 13:49:07 2015
New Revision: 246182

URL: http://llvm.org/viewvc/llvm-project?rev=246182&view=rev
Log:
[Static Analyzer] Make NonNullParamChecker emit implicit null dereference events.

Differential Revision: http://reviews.llvm.org/D11433

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
    cfe/trunk/test/Analysis/nullability.mm

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h?rev=246182&r1=246181&r2=246182&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h Thu Aug 27 13:49:07 2015
@@ -514,6 +514,10 @@ struct ImplicitNullDerefEvent {
   bool IsLoad;
   ExplodedNode *SinkNode;
   BugReporter *BR;
+  // When true, the dereference is in the source code directly. When false, the
+  // dereference might happen later (for example pointer passed to a parameter
+  // that is marked with nonnull attribute.)
+  bool IsDirectDereference;
 };
 
 /// \brief A helper class which wraps a boolean value set to false by default.

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp?rev=246182&r1=246181&r2=246182&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp Thu Aug 27 13:49:07 2015
@@ -220,7 +220,8 @@ void DereferenceChecker::checkLocation(S
     // null or not-null.  Record the error node as an "implicit" null
     // dereference.
     if (ExplodedNode *N = C.generateSink(nullState)) {
-      ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() };
+      ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
+                                      /*IsDirectDereference=*/false};
       dispatchEvent(event);
     }
   }
@@ -257,8 +258,9 @@ void DereferenceChecker::checkBind(SVal
     // At this point the value could be either null or non-null.
     // Record this as an "implicit" null dereference.
     if (ExplodedNode *N = C.generateSink(StNull)) {
-      ImplicitNullDerefEvent event = { V, /*isLoad=*/true, N,
-                                       &C.getBugReporter() };
+      ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
+                                      &C.getBugReporter(),
+                                      /*IsDirectDereference=*/false};
       dispatchEvent(event);
     }
   }

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp?rev=246182&r1=246181&r2=246182&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp Thu Aug 27 13:49:07 2015
@@ -28,7 +28,7 @@ using namespace ento;
 
 namespace {
 class NonNullParamChecker
-  : public Checker< check::PreCall > {
+  : public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
   mutable std::unique_ptr<BugType> BTAttrNonNull;
   mutable std::unique_ptr<BugType> BTNullRefArg;
 
@@ -139,26 +139,34 @@ void NonNullParamChecker::checkPreCall(c
     ProgramStateRef stateNotNull, stateNull;
     std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
 
-    if (stateNull && !stateNotNull) {
-      // Generate an error node.  Check for a null node in case
-      // we cache out.
-      if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
-
-        std::unique_ptr<BugReport> R;
-        if (haveAttrNonNull)
-          R = genReportNullAttrNonNull(errorNode, ArgE);
-        else if (haveRefTypeParam)
-          R = genReportReferenceToNullPointer(errorNode, ArgE);
+    if (stateNull) {
+      if (!stateNotNull) {
+        // Generate an error node.  Check for a null node in case
+        // we cache out.
+        if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
+
+          std::unique_ptr<BugReport> R;
+          if (haveAttrNonNull)
+            R = genReportNullAttrNonNull(errorNode, ArgE);
+          else if (haveRefTypeParam)
+            R = genReportReferenceToNullPointer(errorNode, ArgE);
+
+          // Highlight the range of the argument that was null.
+          R->addRange(Call.getArgSourceRange(idx));
+
+          // Emit the bug report.
+          C.emitReport(std::move(R));
+        }
 
-        // Highlight the range of the argument that was null.
-        R->addRange(Call.getArgSourceRange(idx));
-
-        // Emit the bug report.
-        C.emitReport(std::move(R));
+        // Always return.  Either we cached out or we just emitted an error.
+        return;
+      }
+      if (ExplodedNode *N = C.generateSink(stateNull)) {
+        ImplicitNullDerefEvent event = {
+            V, false, N, &C.getBugReporter(),
+            /*IsDirectDereference=*/haveRefTypeParam};
+        dispatchEvent(event);
       }
-
-      // Always return.  Either we cached out or we just emitted an error.
-      return;
     }
 
     // If a pointer value passed the check we should assume that it is

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp?rev=246182&r1=246181&r2=246182&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp Thu Aug 27 13:49:07 2015
@@ -335,7 +335,10 @@ void NullabilityChecker::checkEvent(Impl
   if (Filter.CheckNullableDereferenced &&
       TrackedNullability->getValue() == Nullability::Nullable) {
     BugReporter &BR = *Event.BR;
-    reportBug(ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
+    if (Event.IsDirectDereference)
+      reportBug(ErrorKind::NullableDereferenced, Event.SinkNode, Region, BR);
+    else
+      reportBug(ErrorKind::NullablePassedToNonnull, Event.SinkNode, Region, BR);
   }
 }
 

Modified: cfe/trunk/test/Analysis/nullability.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/nullability.mm?rev=246182&r1=246181&r2=246182&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/nullability.mm (original)
+++ cfe/trunk/test/Analysis/nullability.mm Thu Aug 27 13:49:07 2015
@@ -50,6 +50,8 @@ int *_Nullable returnsNullableInt();
 
 template <typename T> T *eraseNullab(T *p) { return p; }
 
+void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
+
 void testBasicRules() {
   Dummy *p = returnsNullable();
   int *ptr = returnsNullableInt();
@@ -73,10 +75,8 @@ void testBasicRules() {
     Dummy dd(d);
     break;
   }
-  // Here the copy constructor is called, so a reference is initialized with the
-  // value of p. No ImplicitNullDereference event will be dispatched for this
-  // case. A followup patch is expected to fix this in NonNullParamChecker.
-  default: { Dummy d = *p; } break; // No warning.
+  case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
+  default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
   }
   if (p) {
     takesNonnull(p);




More information about the cfe-commits mailing list