[clang] 3566bbe - [analyzer] Add option for AddrSpace in core.NullDereference check

via cfe-commits cfe-commits at lists.llvm.org
Sun Apr 24 01:52:03 PDT 2022


Author: Vince Bridgers
Date: 2022-04-24T03:51:49-05:00
New Revision: 3566bbe62f2ef2bf1b736d04a9d6b3c669a66297

URL: https://github.com/llvm/llvm-project/commit/3566bbe62f2ef2bf1b736d04a9d6b3c669a66297
DIFF: https://github.com/llvm/llvm-project/commit/3566bbe62f2ef2bf1b736d04a9d6b3c669a66297.diff

LOG: [analyzer] Add option for AddrSpace in core.NullDereference check

    This change adds an option to detect all null dereferences for
    non-default address spaces, except for address spaces 256, 257 and 258.
    Those address spaces are special since null dereferences are not errors.

    All address spaces can be considered (except for 256, 257, and 258) by
    using -analyzer-config
    core.NullDereference:DetectAllNullDereferences=true. This option is
    false by default, retaining the original behavior.

    A LIT test was enhanced to cover this case, and the rst documentation
    was updated to describe this behavior.

Reviewed By: steakhal

Differential Revision: https://reviews.llvm.org/D122841

Added: 
    

Modified: 
    clang/docs/analyzer/checkers.rst
    clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
    clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
    clang/test/Analysis/analyzer-config.c
    clang/test/Analysis/cast-value-notes.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 6e42544c05808..2f5336ae6a67f 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -66,7 +66,20 @@ Check for null pointers passed as arguments to a function whose arguments are re
 
 core.NullDereference (C, C++, ObjC)
 """""""""""""""""""""""""""""""""""
-Check for dereferences of null pointers.
+Check for dereferences of null pointers. 
+
+This checker specifically does
+not report null pointer dereferences for x86 and x86-64 targets when the
+address space is 256 (x86 GS Segment), 257 (x86 FS Segment), or 258 (x86 SS
+segment). See `X86/X86-64 Language Extensions
+<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__
+for reference.
+
+The ``SuppressAddressSpaces`` option suppresses 
+warnings for null dereferences of all pointers with address spaces. You can
+disable this behavior with the option
+``-analyzer-config core.NullDereference:SuppressAddressSpaces=false``.
+*Defaults to true*.
 
 .. code-block:: objc
 

diff  --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index b5ce1eda200c7..1bcbab4985156 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -191,6 +191,13 @@ def CallAndMessageChecker : Checker<"CallAndMessage">,
 
 def DereferenceChecker : Checker<"NullDereference">,
   HelpText<"Check for dereferences of null pointers">,
+  CheckerOptions<[
+    CmdLineOption<Boolean,
+                  "SuppressAddressSpaces",
+                  "Suppresses warning when pointer dereferences an address space",
+                  "true",
+                  Released>
+  ]>,
   Documentation<HasDocumentation>;
 
 def NonNullParamChecker : Checker<"NonNullParamChecker">,

diff  --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 4a9c7ce3c66d8..bb5216266de81 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -11,9 +11,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExprOpenMP.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -39,6 +40,8 @@ class DereferenceChecker
   void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S,
                  CheckerContext &C) const;
 
+  bool suppressReport(CheckerContext &C, const Expr *E) const;
+
 public:
   void checkLocation(SVal location, bool isLoad, const Stmt* S,
                      CheckerContext &C) const;
@@ -49,6 +52,8 @@ class DereferenceChecker
                              const Expr *Ex, const ProgramState *state,
                              const LocationContext *LCtx,
                              bool loadedFrom = false);
+
+  bool SuppressAddressSpaces = false;
 };
 } // end anonymous namespace
 
@@ -109,9 +114,35 @@ static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
   return E;
 }
 
-static bool suppressReport(const Expr *E) {
-  // Do not report dereferences on memory in non-default address spaces.
-  return E->getType().hasAddressSpace();
+bool DereferenceChecker::suppressReport(CheckerContext &C,
+                                        const Expr *E) const {
+  // Do not report dereferences on memory that use address space #256, #257,
+  // and #258. Those address spaces are used when dereferencing address spaces
+  // relative to the GS, FS, and SS segments on x86/x86-64 targets.
+  // Dereferencing a null pointer in these address spaces is not defined
+  // as an error. All other null dereferences in other address spaces
+  // are defined as an error unless explicitly defined.
+  // See https://clang.llvm.org/docs/LanguageExtensions.html, the section
+  // "X86/X86-64 Language Extensions"
+
+  QualType Ty = E->getType();
+  if (!Ty.hasAddressSpace())
+    return false;
+  if (SuppressAddressSpaces)
+    return true;
+
+  const llvm::Triple::ArchType Arch =
+      C.getASTContext().getTargetInfo().getTriple().getArch();
+
+  if ((Arch == llvm::Triple::x86) || (Arch == llvm::Triple::x86_64)) {
+    switch (toTargetAddressSpace(E->getType().getAddressSpace())) {
+    case 256:
+    case 257:
+    case 258:
+      return true;
+    }
+  }
+  return false;
 }
 
 static bool isDeclRefExprToReference(const Expr *E) {
@@ -209,7 +240,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
   // Check for dereference of an undefined value.
   if (l.isUndef()) {
     const Expr *DerefExpr = getDereferenceExpr(S);
-    if (!suppressReport(DerefExpr))
+    if (!suppressReport(C, DerefExpr))
       reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C);
     return;
   }
@@ -230,7 +261,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
       // We know that 'location' can only be null.  This is what
       // we call an "explicit" null dereference.
       const Expr *expr = getDereferenceExpr(S);
-      if (!suppressReport(expr)) {
+      if (!suppressReport(C, expr)) {
         reportBug(DerefKind::NullPointer, nullState, expr, C);
         return;
       }
@@ -272,7 +303,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
   if (StNull) {
     if (!StNonNull) {
       const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
-      if (!suppressReport(expr)) {
+      if (!suppressReport(C, expr)) {
         reportBug(DerefKind::NullPointer, StNull, expr, C);
         return;
       }
@@ -308,7 +339,9 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
 }
 
 void ento::registerDereferenceChecker(CheckerManager &mgr) {
-  mgr.registerChecker<DereferenceChecker>();
+  auto *Chk = mgr.registerChecker<DereferenceChecker>();
+  Chk->SuppressAddressSpaces = mgr.getAnalyzerOptions().getCheckerBooleanOption(
+      mgr.getCurrentCheckerName(), "SuppressAddressSpaces");
 }
 
 bool ento::shouldRegisterDereferenceChecker(const CheckerManager &mgr) {

diff  --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index a166b6f8c4a70..9fed04e941e90 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -41,6 +41,7 @@
 // CHECK-NEXT: core.CallAndMessage:NilReceiver = true
 // CHECK-NEXT: core.CallAndMessage:ParameterCount = true
 // CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
+// CHECK-NEXT: core.NullDereference:SuppressAddressSpaces = true
 // CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
 // CHECK-NEXT: cplusplus.SmartPtrModeling:ModelSmartPtrDereference = false
 // CHECK-NEXT: crosscheck-with-z3 = false

diff  --git a/clang/test/Analysis/cast-value-notes.cpp b/clang/test/Analysis/cast-value-notes.cpp
index 19a9f660f51c6..ddfaf07b2a0af 100644
--- a/clang/test/Analysis/cast-value-notes.cpp
+++ b/clang/test/Analysis/cast-value-notes.cpp
@@ -1,10 +1,44 @@
-// RUN: %clang_analyze_cc1 -std=c++14 \
-// RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
-// RUN:  -analyzer-output=text -verify -DDEFAULT_TRIPLE %s 2>&1 | FileCheck %s -check-prefix=DEFAULT-CHECK
+// RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \
+// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK
+//
+// RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \
+// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN:  -analyzer-config core.NullDereference:SuppressAddressSpaces=false\
+// RUN:  -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK
 //
 // RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \
 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
-// RUN: -analyzer-output=text -verify -DAMDGCN_TRIPLE %s 2>&1 | FileCheck %s -check-prefix=AMDGCN-CHECK
+// RUN:  -analyzer-config core.NullDereference:SuppressAddressSpaces=true\
+// RUN:  -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK
+//
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \
+// RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN:  -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK
+//
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \
+// RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN:  -analyzer-config core.NullDereference:SuppressAddressSpaces=true\
+// RUN:  -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK-SUPPRESSED
+//
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \
+// RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN:  -analyzer-config core.NullDereference:SuppressAddressSpaces=false\
+// RUN:  -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK
+//
+// RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \
+// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN: -analyzer-output=text -verify -DMIPS %s 2>&1
+//
+// RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \
+// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=false\
+// RUN: -analyzer-output=text -verify -DMIPS %s 2>&1
+//
+// RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \
+// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=true\
+// RUN: -analyzer-output=text -verify -DMIPS_SUPPRESSED %s
 
 #include "Inputs/llvm.h"
 
@@ -36,27 +70,51 @@ using namespace clang;
 
 void clang_analyzer_printState();
 
-#if defined(DEFAULT_TRIPLE)
+#if defined(X86)
 void evalReferences(const Shape &S) {
   const auto &C = dyn_cast<Circle>(S);
   // expected-note at -1 {{Assuming 'S' is not a 'Circle'}}
   // expected-note at -2 {{Dereference of null pointer}}
   // expected-warning at -3 {{Dereference of null pointer}}
   clang_analyzer_printState();
-  // DEFAULT-CHECK: "dynamic_types": [
-  // DEFAULT-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const class clang::Circle &", "sub_classable": true }
+  // XX86-CHECK:      "dynamic_types": [
+  // XX86-CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const class clang::Circle &", "sub_classable": true }
   (void)C;
 }
-#elif defined(AMDGCN_TRIPLE)
-void evalReferences(const Shape &S) {
+#if defined(SUPPRESSED)
+void evalReferences_addrspace(const Shape &S) {
   const auto &C = dyn_cast<DEVICE Circle>(S);
   clang_analyzer_printState();
-  // AMDGCN-CHECK: "dynamic_types": [
-  // AMDGCN-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }
+  // X86-CHECK-SUPPRESSED: "dynamic_types": [
+  // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }
   (void)C;
 }
-#else
-#error Target must be specified, and must be pinned
+#endif
+#if defined(NOT_SUPPRESSED)
+void evalReferences_addrspace(const Shape &S) {
+  const auto &C = dyn_cast<DEVICE Circle>(S);
+  // expected-note at -1 {{Assuming 'S' is not a 'Circle'}}
+  // expected-note at -2 {{Dereference of null pointer}}
+  // expected-warning at -3 {{Dereference of null pointer}}
+  clang_analyzer_printState();
+  // X86-CHECK: "dynamic_types": [
+  // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }
+  (void)C;
+}
+#endif
+#elif defined(MIPS)
+void evalReferences(const Shape &S) {
+  const auto &C = dyn_cast<Circle>(S);
+  // expected-note at -1 {{Assuming 'S' is not a 'Circle'}}
+  // expected-note at -2 {{Dereference of null pointer}}
+  // expected-warning at -3 {{Dereference of null pointer}}
+}
+#if defined(MIPS_SUPPRESSED)
+void evalReferences_addrspace(const Shape &S) {
+  const auto &C = dyn_cast<DEVICE Circle>(S);
+  (void)C;
+}
+#endif
 #endif
 
 void evalNonNullParamNonNullReturnReference(const Shape &S) {


        


More information about the cfe-commits mailing list