diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index b73233458a5e6..31593d7808e70 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -118,21 +118,6 @@ core.NullDereference (C, C++, ObjC) """"""""""""""""""""""""""""""""""" 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 -`__ -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``. -Value of this option is also used for checker -:ref:`_alpha-core-FixedAddressDereference`. -*Defaults to true*. - .. code-block:: objc // C @@ -172,6 +157,16 @@ Value of this option is also used for checker obj->x = 1; // warn } +Null pointer dereferences of pointers with address spaces are not always defined +as error. Specifically on x86/x86-64 target if the pointer address space is +256 (x86 GS Segment), 257 (x86 FS Segment), or 258 (x86 SS Segment), a null +dereference is not defined as error. See `X86/X86-64 Language Extensions +`__ +for reference. The ``suppress-all-address-spaces`` configuration option can be +used to control if null dereferences with any address space or only with the +specific x86 address spaces 256, 257, 258 are excluded from reporting as error. +The default is all address spaces. + .. _core-StackAddressEscape: core.StackAddressEscape (C) @@ -2926,6 +2921,9 @@ Check for assignment of a fixed address to a pointer. alpha.core.FixedAddressDereference (C, C++, ObjC) """"""""""""""""""""""""""""""""""""""""""""""""" Check for dereferences of fixed addresses. +A pointer contains a fixed address if it was set to a hard-coded value or it +becomes otherwise obvious that at that point it can have only a single specific +value. .. code-block:: c @@ -2945,17 +2943,10 @@ Check for dereferences of fixed addresses. int x = (*p_function)('x', 'y'); // NO warning yet at functon pointer calls } -Similarly to :ref:`_core-NullDereference`, the checker intentionally does -not report 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 -`__ -for reference.) - -If you want to disable this behavior, set the ``SuppressAddressSpaces`` option -of checker ``core.NullDereference`` to false, like -``-analyzer-config core.NullDereference:SuppressAddressSpaces=false``. The value -of this option is used for both checkers. +The analyzer option ``suppress-all-address-spaces`` affects this checker. If it +is set to true pointer dereferences with any address space are not reported as +error. Otherwise only address spaces 256, 257, 258 on target x86/x86-64 are +excluded from reporting as error. The default is all address spaces. .. _alpha-core-PointerArithm: diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index aacc90fafd9c1..679789c239fcc 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -213,13 +213,6 @@ def DereferenceModeling : Checker<"DereferenceModeling">, def NullDereferenceChecker : Checker<"NullDereference">, HelpText<"Check for dereferences of null pointers">, - CheckerOptions<[ - CmdLineOption - ]>, Documentation, Dependencies<[DereferenceModeling]>; diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index a9b8d0753673b..f1553397cdae1 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -395,6 +395,19 @@ ANALYZER_OPTION( "flex\" won't be analyzed.", true) +ANALYZER_OPTION( + bool, ShouldSuppressAddressSpaces, "suppress-all-address-spaces", + "The analyzer does 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. " + "When this option is turned on, the special behavior of address spaces " + "#256, #257, #258 is extended to all pointers with address spaces and on " + "any target.", + true) + //===----------------------------------------------------------------------===// // Unsigned analyzer options. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 750d96c85147e..deda009f390a4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -54,8 +54,6 @@ class DereferenceChecker const LocationContext *LCtx, bool loadedFrom = false); - bool SuppressAddressSpaces = false; - bool CheckNullDereference = false; bool CheckFixedDereference = false; @@ -137,7 +135,7 @@ bool DereferenceChecker::suppressReport(CheckerContext &C, QualType Ty = E->getType(); if (!Ty.hasAddressSpace()) return false; - if (SuppressAddressSpaces) + if (C.getAnalysisManager().getAnalyzerOptions().ShouldSuppressAddressSpaces) return true; const llvm::Triple::ArchType Arch = @@ -405,8 +403,6 @@ bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) { void ento::registerNullDereferenceChecker(CheckerManager &Mgr) { auto *Chk = Mgr.getChecker(); Chk->CheckNullDereference = true; - Chk->SuppressAddressSpaces = Mgr.getAnalyzerOptions().getCheckerBooleanOption( - Mgr.getCurrentCheckerName(), "SuppressAddressSpaces"); Chk->BT_Null.reset(new BugType(Mgr.getCurrentCheckerName(), "Dereference of null pointer", categories::LogicError)); diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index f6a49680917ac..6ce2a26c9119c 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -37,7 +37,6 @@ // 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 @@ -124,6 +123,7 @@ // CHECK-NEXT: silence-checkers = "" // CHECK-NEXT: stable-report-filename = false // CHECK-NEXT: support-symbolic-integer-casts = false +// CHECK-NEXT: suppress-all-address-spaces = true // CHECK-NEXT: suppress-c++-stdlib = true // CHECK-NEXT: suppress-inlined-defensive-checks = true // CHECK-NEXT: suppress-null-return-paths = true diff --git a/clang/test/Analysis/cast-value-notes.cpp b/clang/test/Analysis/cast-value-notes.cpp index 7ee224dc6e5d8..38957bd099cbd 100644 --- a/clang/test/Analysis/cast-value-notes.cpp +++ b/clang/test/Analysis/cast-value-notes.cpp @@ -4,12 +4,12 @@ // // 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-config suppress-all-address-spaces=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-config core.NullDereference:SuppressAddressSpaces=true\ +// RUN: -analyzer-config suppress-all-address-spaces=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 \ @@ -18,12 +18,12 @@ // // 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-config suppress-all-address-spaces=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-config suppress-all-address-spaces=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 \ @@ -32,12 +32,12 @@ // // 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-config suppress-all-address-spaces=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-config suppress-all-address-spaces=true\ // RUN: -analyzer-output=text -verify -DMIPS_SUPPRESSED %s #include "Inputs/llvm.h" diff --git a/clang/test/Analysis/concrete-address.c b/clang/test/Analysis/concrete-address.c index 3121eeec1c1d1..683b7f29f4611 100644 --- a/clang/test/Analysis/concrete-address.c +++ b/clang/test/Analysis/concrete-address.c @@ -142,22 +142,3 @@ void f9() { // FIXME: there should be a warning from calling the function pointer with fixed address int x = (*p_function) ('x', 'y'); } - -#define AS_ATTRIBUTE volatile __attribute__((address_space(256))) -#define _get_base() ((void * AS_ATTRIBUTE *)0x10) - -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 == (int *)0x10) { - *cpu_data = 3; // no-warning - } -} -struct X { int member; }; -int test_address_space_member(void) { - struct X AS_ATTRIBUTE *data = (struct X AS_ATTRIBUTE *)0x10UL; - int ret; - ret = data->member; // no-warning - return ret; -} diff --git a/clang/test/Analysis/suppress-all-address-spaces.c b/clang/test/Analysis/suppress-all-address-spaces.c new file mode 100644 index 0000000000000..8daa75e0470aa --- /dev/null +++ b/clang/test/Analysis/suppress-all-address-spaces.c @@ -0,0 +1,77 @@ +// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-config suppress-all-address-spaces=false -verify=x86-nosuppress %s +// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,alpha.core -std=gnu99 -verify=x86-suppress %s +// RUN: %clang_analyze_cc1 -triple arm-pc-linux-gnu -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-config suppress-all-address-spaces=false -verify=other-nosuppress %s +// RUN: %clang_analyze_cc1 -triple arm-pc-linux-gnu -analyzer-checker=core,alpha.core -std=gnu99 -verify=other-suppress %s + +#define AS_ATTRIBUTE(_X) volatile __attribute__((address_space(_X))) + +#define _get_base() ((void * AS_ATTRIBUTE(256) *)0) + +void* test_address_space_array(unsigned long slot) { + return _get_base()[slot]; // other-nosuppress-warning{{Dereference}} +} + +void test_address_space_condition(int AS_ATTRIBUTE(257) *cpu_data) { + if (cpu_data == 0) { + *cpu_data = 3; // other-nosuppress-warning{{Dereference}} + } +} + +struct X { int member; }; +int test_address_space_member(void) { + struct X AS_ATTRIBUTE(258) *data = (struct X AS_ATTRIBUTE(258) *)0UL; + int ret; + ret = data->member; // other-nosuppress-warning{{Dereference}} + return ret; +} + +void test_other_address_space_condition(int AS_ATTRIBUTE(259) *cpu_data) { + if (cpu_data == 0) { + *cpu_data = 3; // other-nosuppress-warning{{Dereference}} \ + // x86-nosuppress-warning{{Dereference}} + } +} + +void test_no_address_space_condition(int *cpu_data) { + if (cpu_data == 0) { + *cpu_data = 3; // other-nosuppress-warning{{Dereference}} \ + // x86-nosuppress-warning{{Dereference}} \ + // other-suppress-warning{{Dereference}} \ + // x86-suppress-warning{{Dereference}} + } +} + +#define _fixed_get_base() ((void * AS_ATTRIBUTE(256) *)2) + +void* fixed_test_address_space_array(unsigned long slot) { + return _fixed_get_base()[slot]; // other-nosuppress-warning{{Dereference}} +} + +void fixed_test_address_space_condition(int AS_ATTRIBUTE(257) *cpu_data) { + if (cpu_data == (int AS_ATTRIBUTE(257) *)2) { + *cpu_data = 3; // other-nosuppress-warning{{Dereference}} + } +} + +int fixed_test_address_space_member(void) { + struct X AS_ATTRIBUTE(258) *data = (struct X AS_ATTRIBUTE(258) *)2UL; + int ret; + ret = data->member; // other-nosuppress-warning{{Dereference}} + return ret; +} + +void fixed_test_other_address_space_condition(int AS_ATTRIBUTE(259) *cpu_data) { + if (cpu_data == (int AS_ATTRIBUTE(259) *)2) { + *cpu_data = 3; // other-nosuppress-warning{{Dereference}} \ + // x86-nosuppress-warning{{Dereference}} + } +} + +void fixed_test_no_address_space_condition(int *cpu_data) { + if (cpu_data == (int *)2) { + *cpu_data = 3; // other-nosuppress-warning{{Dereference}} \ + // x86-nosuppress-warning{{Dereference}} \ + // other-suppress-warning{{Dereference}} \ + // x86-suppress-warning{{Dereference}} +} +}