[analyzer] Don't report null dereferences on address_space annotated memory

llvm-svn: 256885
diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 5dd2832..f216f696 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -34,8 +34,7 @@
   mutable std::unique_ptr<BuiltinBug> BT_null;
   mutable std::unique_ptr<BuiltinBug> BT_undef;
 
-  void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C,
-                 bool IsBind = false) const;
+  void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C) const;
 
 public:
   void checkLocation(SVal location, bool isLoad, const Stmt* S,
@@ -89,8 +88,31 @@
   }
 }
 
+static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
+  const Expr *E = nullptr;
+
+  // Walk through lvalue casts to get the original expression
+  // that syntactically caused the load.
+  if (const Expr *expr = dyn_cast<Expr>(S))
+    E = expr->IgnoreParenLValueCasts();
+
+  if (IsBind) {
+    const VarDecl *VD;
+    const Expr *Init;
+    std::tie(VD, Init) = parseAssignment(S);
+    if (VD && Init)
+      E = Init;
+  }
+  return E;
+}
+
+static bool suppressReport(const Expr *E) {
+  // Do not report dereferences on memory in non-default address spaces.
+  return E->getType().getQualifiers().hasAddressSpace();
+}
+
 void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
-                                   CheckerContext &C, bool IsBind) const {
+                                   CheckerContext &C) const {
   // Generate an error node.
   ExplodedNode *N = C.generateErrorNode(State);
   if (!N)
@@ -106,19 +128,6 @@
 
   SmallVector<SourceRange, 2> Ranges;
 
-  // Walk through lvalue casts to get the original expression
-  // that syntactically caused the load.
-  if (const Expr *expr = dyn_cast<Expr>(S))
-    S = expr->IgnoreParenLValueCasts();
-
-  if (IsBind) {
-    const VarDecl *VD;
-    const Expr *Init;
-    std::tie(VD, Init) = parseAssignment(S);
-    if (VD && Init)
-      S = Init;
-  }
-
   switch (S->getStmtClass()) {
   case Stmt::ArraySubscriptExprClass: {
     os << "Array access";
@@ -209,8 +218,11 @@
   // The explicit NULL case.
   if (nullState) {
     if (!notNullState) {
-      reportBug(nullState, S, C);
-      return;
+      const Expr *expr = getDereferenceExpr(S);
+      if (!suppressReport(expr)) {
+        reportBug(nullState, expr, C);
+        return;
+      }
     }
 
     // Otherwise, we have the case where the location could either be
@@ -248,8 +260,11 @@
 
   if (StNull) {
     if (!StNonNull) {
-      reportBug(StNull, S, C, /*isBind=*/true);
-      return;
+      const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
+      if (!suppressReport(expr)) {
+        reportBug(StNull, expr, C);
+        return;
+      }
     }
 
     // At this point the value could be either null or non-null.
diff --git a/clang/test/Analysis/null-deref-ps.c b/clang/test/Analysis/null-deref-ps.c
index 240e8ed..79b3b3a 100644
--- a/clang/test/Analysis/null-deref-ps.c
+++ b/clang/test/Analysis/null-deref-ps.c
@@ -311,3 +311,21 @@
       return *p; // no-warning
   return 0;
 }
+
+#define AS_ATTRIBUTE volatile __attribute__((address_space(256)))
+#define _get_base() ((void * AS_ATTRIBUTE *)0)
+void* test_address_space_array(unsigned long slot) {
+  return _get_base()[slot]; // no-warning
+}
+void test_address_space_condition(int AS_ATTRIBUTE *cpu_data) {
+   if (cpu_data == 0) {
+    *cpu_data = 3; // no-warning
+  }
+}
+struct X { int member; };
+int test_address_space_member() {
+  struct X AS_ATTRIBUTE *data = (struct X AS_ATTRIBUTE *)0UL;
+  int ret;
+  ret = data->member; // no-warning
+  return ret;
+}
diff --git a/clang/test/Analysis/nullptr.cpp b/clang/test/Analysis/nullptr.cpp
index 17320f3..acc525e 100644
--- a/clang/test/Analysis/nullptr.cpp
+++ b/clang/test/Analysis/nullptr.cpp
@@ -126,3 +126,22 @@
 void fromReturnType() {
   ((X *)returnsNullPtrType())->f(); // expected-warning{{Called C++ object pointer is null}}
 }
+
+#define AS_ATTRIBUTE __attribute__((address_space(256)))
+class AS1 {
+public:
+  int x;
+  ~AS1() {
+    int AS_ATTRIBUTE *x = 0;
+    *x = 3; // no-warning
+  }
+};
+void test_address_space_field_access() {
+  AS1 AS_ATTRIBUTE *pa = 0;
+  pa->x = 0; // no-warning
+}
+void test_address_space_bind() {
+  AS1 AS_ATTRIBUTE *pa = 0;
+  AS1 AS_ATTRIBUTE &r = *pa;
+  r.x = 0; // no-warning
+}