https://github.com/balazske updated https://github.com/llvm/llvm-project/pull/127191
From 1f2ad6d5ce6f11fb031ec2175527f56ea86761ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com> Date: Mon, 3 Feb 2025 15:35:31 +0100 Subject: [PATCH 1/5] [clang][analyzer] Add checker 'alpha.core.FixedAddressDereference' --- clang/docs/analyzer/checkers.rst | 38 ++++ .../clang/StaticAnalyzer/Checkers/Checkers.td | 26 +-- .../Checkers/DereferenceChecker.cpp | 63 ++++++- clang/test/Analysis/concrete-address.c | 162 +++++++++++++++++- clang/test/Analysis/misc-ps.m | 4 +- 5 files changed, 271 insertions(+), 22 deletions(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 707067358fdfe..c5e10f5a8bbf2 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -129,6 +129,8 @@ 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 used for checker :ref:`_core-FixedAddressDereference` +too. *Defaults to true*. .. code-block:: objc @@ -2919,6 +2921,42 @@ Check for assignment of a fixed address to a pointer. p = (int *) 0x10000; // warn } +.. _alpha-core-FixedAddressDereference: + +alpha.core.FixedAddressDereference (C, C++, ObjC) +""""""""""""""""""""""""""""""""""""""""""""""""" +Check for dereferences of fixed values used as pointers. + +Similarly as at :ref:`_core-NullDereference`, the checker specifically 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 +<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__ +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. + +.. code-block:: c + + void test1() { + int *p = (int *)0x020; + int x = p[0]; // warn + } + + void test2(int *p) { + if (p == (int *)-1) + *p = 0; // warn + } + + void test3() { + int (*p_function)(char, char); + p_function = (int (*)(char, char))0x04080; + int x = (*p_function)('x', 'y'); // NO warning yet at functon pointer calls + } + .. _alpha-core-PointerArithm: alpha.core.PointerArithm (C) diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 9bf491eac1e0e..44ca28c003b06 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -211,17 +211,15 @@ def DereferenceModeling : Checker<"DereferenceModeling">, Documentation<NotDocumented>, Hidden; -def NullDereferenceChecker : 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>, - Dependencies<[DereferenceModeling]>; +def NullDereferenceChecker + : 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>, + Dependencies<[DereferenceModeling]>; def NonNullParamChecker : Checker<"NonNullParamChecker">, HelpText<"Check for null pointers passed as arguments to a function whose " @@ -285,6 +283,12 @@ def FixedAddressChecker : Checker<"FixedAddr">, HelpText<"Check for assignment of a fixed address to a pointer">, Documentation<HasDocumentation>; +def FixedAddressDereferenceChecker + : Checker<"FixedAddressDereference">, + HelpText<"Check for dereferences of fixed values used as pointers">, + Documentation<HasDocumentation>, + Dependencies<[DereferenceModeling]>; + def PointerArithChecker : Checker<"PointerArithm">, HelpText<"Check for pointer arithmetic on locations other than array " "elements">, diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index e9e2771c739b6..6a3f70e62e77b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -31,7 +31,12 @@ class DereferenceChecker : public Checker< check::Location, check::Bind, EventDispatcher<ImplicitNullDerefEvent> > { - enum DerefKind { NullPointer, UndefinedPointerValue, AddressOfLabel }; + enum DerefKind { + NullPointer, + UndefinedPointerValue, + AddressOfLabel, + FixedAddress + }; void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, CheckerContext &C) const; @@ -52,10 +57,12 @@ class DereferenceChecker bool SuppressAddressSpaces = false; bool CheckNullDereference = false; + bool CheckFixedDereference = false; std::unique_ptr<BugType> BT_Null; std::unique_ptr<BugType> BT_Undef; std::unique_ptr<BugType> BT_Label; + std::unique_ptr<BugType> BT_FixedAddress; }; } // end anonymous namespace @@ -155,30 +162,47 @@ static bool isDeclRefExprToReference(const Expr *E) { void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, CheckerContext &C) const { - if (!CheckNullDereference) { - C.addSink(); - return; - } - const BugType *BT = nullptr; llvm::StringRef DerefStr1; llvm::StringRef DerefStr2; switch (K) { case DerefKind::NullPointer: + if (!CheckNullDereference) { + C.addSink(); + return; + } BT = BT_Null.get(); DerefStr1 = " results in a null pointer dereference"; DerefStr2 = " results in a dereference of a null pointer"; break; case DerefKind::UndefinedPointerValue: + if (!CheckNullDereference) { + C.addSink(); + return; + } BT = BT_Undef.get(); DerefStr1 = " results in an undefined pointer dereference"; DerefStr2 = " results in a dereference of an undefined pointer value"; break; case DerefKind::AddressOfLabel: + if (!CheckNullDereference) { + C.addSink(); + return; + } BT = BT_Label.get(); DerefStr1 = " results in an undefined pointer dereference"; DerefStr2 = " results in a dereference of an address of a label"; break; + case DerefKind::FixedAddress: + // Deliberately don't add a sink node if check is disabled. + // This situation may be valid in special cases. + if (!CheckFixedDereference) + return; + + BT = BT_FixedAddress.get(); + DerefStr1 = " results in a dereference of a fixed address"; + DerefStr2 = " results in a dereference of a fixed address"; + break; }; // Generate an error node. @@ -289,6 +313,13 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, } } + if (location.isConstant()) { + const Expr *DerefExpr = getDereferenceExpr(S, isLoad); + if (!suppressReport(C, DerefExpr)) + reportBug(DerefKind::FixedAddress, notNullState, DerefExpr, C); + return; + } + // From this point forward, we know that the location is not null. C.addTransition(notNullState); } @@ -337,6 +368,13 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, } } + if (V.isConstant()) { + const Expr *DerefExpr = getDereferenceExpr(S, true); + if (!suppressReport(C, DerefExpr)) + reportBug(DerefKind::FixedAddress, State, DerefExpr, C); + return; + } + // Unlike a regular null dereference, initializing a reference with a // dereferenced null pointer does not actually cause a runtime exception in // Clang's implementation of references. @@ -383,3 +421,16 @@ void ento::registerNullDereferenceChecker(CheckerManager &Mgr) { bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { return true; } + +void ento::registerFixedAddressDereferenceChecker(CheckerManager &Mgr) { + auto *Chk = Mgr.getChecker<DereferenceChecker>(); + Chk->CheckFixedDereference = true; + Chk->BT_FixedAddress.reset(new BugType(Mgr.getCurrentCheckerName(), + "Dereference of a fixed address", + categories::LogicError)); +} + +bool ento::shouldRegisterFixedAddressDereferenceChecker( + const CheckerManager &) { + return true; +} diff --git a/clang/test/Analysis/concrete-address.c b/clang/test/Analysis/concrete-address.c index 346f5093e44f7..af99aa43a98a8 100644 --- a/clang/test/Analysis/concrete-address.c +++ b/clang/test/Analysis/concrete-address.c @@ -1,7 +1,163 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -verify %s -// expected-no-diagnostics -void foo(void) { +extern void __assert_fail (__const char *__assertion, __const char *__file, + unsigned int __line, __const char *__function) + __attribute__ ((__noreturn__)); + +#define assert(expr) \ + ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) + +typedef unsigned long uintptr_t; + +void f0(void) { int *p = (int*) 0x10000; // Should not crash here. - *p = 3; + *p = 3; // expected-warning{{Dereference of a fixed address}} +} + +void f1(int *p) { + if (p != (int *)-1) + *p = 1; + else + *p = 0; // expected-warning{{Dereference of a fixed address}} +} + +struct f2_struct { + int x; +}; + +int f2(struct f2_struct* p) { + + if (p != (struct f2_struct *)1) + p->x = 1; + + return p->x++; // expected-warning{{Access to field 'x' results in a dereference of a fixed address (loaded from variable 'p')}} +} + +int f3_1(char* x) { + int i = 2; + + if (x != (char *)1) + return x[i - 1]; + + return x[i+1]; // expected-warning{{Array access (from variable 'x') results in a dereference of a fixed address}} +} + +int f3_2(char* x) { + int i = 2; + + if (x != (char *)1) + return x[i - 1]; + + return x[i+1]++; // expected-warning{{Array access (from variable 'x') results in a dereference of a fixed address}} +} + +int f4_1(int *p) { + uintptr_t x = (uintptr_t) p; + + if (x != (uintptr_t)1) + return 1; + + int *q = (int*) x; + return *q; // expected-warning{{Dereference of a fixed address (loaded from variable 'q')}} +} + +int f4_2(void) { + short array[2]; + uintptr_t x = (uintptr_t)array; + short *p = (short *)x; + + // The following branch should be infeasible. + if (!(p == &array[0])) { + p = (short *)1; + *p = 1; // no-warning + } + + if (p != (short *)1) { + *p = 5; // no-warning + p = (short *)1; // expected-warning {{Using a fixed address is not portable}} + } + else return 1; + + *p += 10; // expected-warning{{Dereference of a fixed}} + return 0; +} + +int f5(void) { + char *s = "hello world"; + return s[0]; // no-warning +} + +void f6(int *p, int *q) { + if (p != (int *)1) + if (p == (int *)1) + *p = 1; // no-warning + + if (q == (int *)1) + if (q != (int *)1) + *q = 1; // no-warning +} + +int* qux(int); + +int f7_1(unsigned len) { + assert (len != 0); + int *p = (int *)1; + unsigned i; + + for (i = 0; i < len; ++i) + p = qux(i); + + return *p++; // no-warning +} + +int f7_2(unsigned len) { + assert (len > 0); // note use of '>' + int *p = (int *)1; + unsigned i; + + for (i = 0; i < len; ++i) + p = qux(i); + + return *p++; // no-warning +} + +struct f8_s { + int x; + int y[2]; +}; + +void f8(struct f8_s *s, int coin) { + if (s != (struct f8_s *)7) + return; + + if (coin) + s->x = 5; // expected-warning{{Access to field 'x' results in a dereference of a fixed address (loaded from variable 's')}} + else + s->y[1] = 6; // expected-warning{{Array access (via field 'y') results in a dereference of a fixed address}} +} + +void f9() { + int (*p_function) (char, char) = (int (*)(char, char))0x04040; // FIXME: warn at this initialization + p_function = (int (*)(char, char))0x04080; // expected-warning {{Using a fixed address is not portable}} + // 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/misc-ps.m b/clang/test/Analysis/misc-ps.m index 0a8a30cb6175c..841f618fbdfab 100644 --- a/clang/test/Analysis/misc-ps.m +++ b/clang/test/Analysis/misc-ps.m @@ -1,6 +1,6 @@ // NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued. -// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -Wno-strict-prototypes -Wno-pointer-to-int-cast -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s -// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -Wno-strict-prototypes -Wno-pointer-to-int-cast -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s +// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-disable-checker=alpha.core.FixedAddressDereference -Wno-strict-prototypes -Wno-pointer-to-int-cast -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s +// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,alpha.core,osx.cocoa.AtSync -analyzer-disable-checker=alpha.core.FixedAddressDereference -Wno-strict-prototypes -Wno-pointer-to-int-cast -verify -fblocks -Wno-unreachable-code -Wno-null-dereference -Wno-objc-root-class %s #ifndef __clang_analyzer__ #error __clang_analyzer__ not defined From d60d9c7f64ba501f80ee24db7afa9be9beec2cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com> Date: Fri, 14 Feb 2025 11:50:27 +0100 Subject: [PATCH 2/5] fix link in documentation --- clang/docs/analyzer/checkers.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index c5e10f5a8bbf2..6480c423bdce7 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -129,8 +129,8 @@ 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 used for checker :ref:`_core-FixedAddressDereference` -too. +Value of this option is used for checker +:ref:`_alpha-core-FixedAddressDereference` too. *Defaults to true*. .. code-block:: objc From 69f42e9b7eeeba41d98393c366971ee307b0bbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com> Date: Mon, 17 Feb 2025 15:00:17 +0100 Subject: [PATCH 3/5] addressing review comments --- clang/docs/analyzer/checkers.rst | 30 +++++++++---------- .../clang/StaticAnalyzer/Checkers/Checkers.td | 22 +++++++------- .../Checkers/DereferenceChecker.cpp | 2 +- clang/test/Analysis/concrete-address.c | 2 +- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 6480c423bdce7..b73233458a5e6 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -129,8 +129,8 @@ 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 used for checker -:ref:`_alpha-core-FixedAddressDereference` too. +Value of this option is also used for checker +:ref:`_alpha-core-FixedAddressDereference`. *Defaults to true*. .. code-block:: objc @@ -2925,19 +2925,7 @@ Check for assignment of a fixed address to a pointer. alpha.core.FixedAddressDereference (C, C++, ObjC) """"""""""""""""""""""""""""""""""""""""""""""""" -Check for dereferences of fixed values used as pointers. - -Similarly as at :ref:`_core-NullDereference`, the checker specifically 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 -<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__ -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. +Check for dereferences of fixed addresses. .. code-block:: c @@ -2957,6 +2945,18 @@ of this option is used for both checkers. 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 +<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__ +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. + .. _alpha-core-PointerArithm: alpha.core.PointerArithm (C) diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 44ca28c003b06..aacc90fafd9c1 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -211,15 +211,17 @@ def DereferenceModeling : Checker<"DereferenceModeling">, Documentation<NotDocumented>, Hidden; -def NullDereferenceChecker - : 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>, - Dependencies<[DereferenceModeling]>; +def NullDereferenceChecker : 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>, + Dependencies<[DereferenceModeling]>; def NonNullParamChecker : Checker<"NonNullParamChecker">, HelpText<"Check for null pointers passed as arguments to a function whose " @@ -285,7 +287,7 @@ def FixedAddressChecker : Checker<"FixedAddr">, def FixedAddressDereferenceChecker : Checker<"FixedAddressDereference">, - HelpText<"Check for dereferences of fixed values used as pointers">, + HelpText<"Check for dereferences of fixed addresses">, Documentation<HasDocumentation>, Dependencies<[DereferenceModeling]>; diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 6a3f70e62e77b..750d96c85147e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -35,7 +35,7 @@ class DereferenceChecker NullPointer, UndefinedPointerValue, AddressOfLabel, - FixedAddress + FixedAddress, }; void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, diff --git a/clang/test/Analysis/concrete-address.c b/clang/test/Analysis/concrete-address.c index af99aa43a98a8..3121eeec1c1d1 100644 --- a/clang/test/Analysis/concrete-address.c +++ b/clang/test/Analysis/concrete-address.c @@ -7,7 +7,7 @@ extern void __assert_fail (__const char *__assertion, __const char *__file, #define assert(expr) \ ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) -typedef unsigned long uintptr_t; +typedef unsigned long long uintptr_t; void f0(void) { int *p = (int*) 0x10000; // Should not crash here. From 080431c71ddfb0f761fb8c188a316494853ca811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com> Date: Tue, 18 Feb 2025 16:40:48 +0100 Subject: [PATCH 4/5] checker option moved to configuration option --- clang/docs/analyzer/checkers.rst | 43 ++++------- .../clang/StaticAnalyzer/Checkers/Checkers.td | 7 -- .../StaticAnalyzer/Core/AnalyzerOptions.def | 13 ++++ .../Checkers/DereferenceChecker.cpp | 6 +- clang/test/Analysis/analyzer-config.c | 2 +- clang/test/Analysis/cast-value-notes.cpp | 12 +-- clang/test/Analysis/concrete-address.c | 19 ----- .../Analysis/suppress-all-address-spaces.c | 77 +++++++++++++++++++ 8 files changed, 115 insertions(+), 64 deletions(-) create mode 100644 clang/test/Analysis/suppress-all-address-spaces.c 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 -<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``. -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 +<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__ +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 -<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__ -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<Boolean, - "SuppressAddressSpaces", - "Suppresses warning when pointer dereferences an address space", - "true", - Released> - ]>, Documentation<HasDocumentation>, 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<DereferenceChecker>(); 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}} +} +} From 00ae0c6fc31df880e778fbe2f71730679a27d581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.k...@ericsson.com> Date: Fri, 21 Feb 2025 14:57:46 +0100 Subject: [PATCH 5/5] small NFC fixes --- clang/docs/analyzer/checkers.rst | 1 + clang/test/Analysis/suppress-all-address-spaces.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 31593d7808e70..cf233f729ff2d 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -2921,6 +2921,7 @@ 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. diff --git a/clang/test/Analysis/suppress-all-address-spaces.c b/clang/test/Analysis/suppress-all-address-spaces.c index 8daa75e0470aa..e74e34e84482e 100644 --- a/clang/test/Analysis/suppress-all-address-spaces.c +++ b/clang/test/Analysis/suppress-all-address-spaces.c @@ -73,5 +73,5 @@ void fixed_test_no_address_space_condition(int *cpu_data) { // x86-nosuppress-warning{{Dereference}} \ // other-suppress-warning{{Dereference}} \ // x86-suppress-warning{{Dereference}} -} + } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits