[clang][analyzer] Add checker 'alpha.core.FixedAddressDereference' by balazske · Pull Request #127191 · llvm/llvm-project (original) (raw)

Conversation

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters

[ Show hidden characters]({{ revealButtonHref }})

@balazske

@balazske

@llvmbot

@llvm/pr-subscribers-clang

Author: Balázs Kéri (balazske)

Changes


Full diff: https://github.com/llvm/llvm-project/pull/127191.diff

5 Files Affected:

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, 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, - 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, + 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; +def FixedAddressDereferenceChecker + : Checker<"FixedAddressDereference">, + HelpText<"Check for dereferences of fixed values used as pointers">, + Documentation, + 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 > { - 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 BT_Null; std::unique_ptr BT_Undef; std::unique_ptr BT_Label; + std::unique_ptr 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:

};

// Generate an error node. @@ -289,6 +313,13 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, } }

+} + +bool ento::shouldRegisterFixedAddressDereferenceChecker(

-void foo(void) { +extern void __assert_fail (__const char *__assertion, __const char *__file,

+} + +struct f2_struct {

+} + +int* qux(int); + +int f7_1(unsigned len) {

+} + +void f9() {

+#define _get_base() ((void * AS_ATTRIBUTE )0x10) + +void test_address_space_array(unsigned long slot) {

#ifndef clang_analyzer #error clang_analyzer not defined

@llvmbot

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balázs Kéri (balazske)

Changes


Full diff: https://github.com/llvm/llvm-project/pull/127191.diff

5 Files Affected:

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, 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, - 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, + 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; +def FixedAddressDereferenceChecker + : Checker<"FixedAddressDereference">, + HelpText<"Check for dereferences of fixed values used as pointers">, + Documentation, + 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 > { - 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 BT_Null; std::unique_ptr BT_Undef; std::unique_ptr BT_Label; + std::unique_ptr 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:

};

// Generate an error node. @@ -289,6 +313,13 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, } }

+} + +bool ento::shouldRegisterFixedAddressDereferenceChecker(

-void foo(void) { +extern void __assert_fail (__const char *__assertion, __const char *__file,

+} + +struct f2_struct {

+} + +int* qux(int); + +int f7_1(unsigned len) {

+} + +void f9() {

+#define _get_base() ((void * AS_ATTRIBUTE )0x10) + +void test_address_space_array(unsigned long slot) {

#ifndef clang_analyzer #error clang_analyzer not defined

@balazske

@balazske

The checker is alpha because there are known problems with it which I plan to fix later.
A problem is with the bugpath messages where a constant pointer was assumed to be a null pointer but after this checker (or even before it?) this is not true.

steakhal

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the impression that the core dereference checker already checks this.

@balazske

It may cause confusion that "NullDereference" checker checks not only null dereference but undefined pointer and label address too. Probably these checks (specially label address) can be moved into this checker. (Or add the new check to NullDereference without a new checker?)

@steakhal

It may cause confusion that "NullDereference" checker checks not only null dereference but undefined pointer and label address too. Probably these checks (specially label address) can be moved into this checker. (Or add the new check to NullDereference without a new checker?)

I see. Thanks.
I dont have a firm opinion on the architecture. Usually we should go with what is more natural. If there would be signifficat semantic sharing, then a single checker works usually better. Its up to you.

steakhal

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Thank you!

@balazske

@steakhal

I've marked the resolved comments. There are a few unresolved conversations left.

@balazske

steakhal

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with your PR. I think it looks great.

// x86-nosuppress-warning{{Dereference}} \
// other-suppress-warning{{Dereference}} \
// x86-suppress-warning{{Dereference}}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@balazske

NagyDonat

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I like the change, but I feel that the analyzer option name suppress-all-address-spaces is too misleading (see inline comment for more detailed suggestion).

Comment on lines 165 to 168

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
for reference.
If the analyzer option ``suppress-all-address-spaces`` is set to true (the
default value), then this checker never reports dereference of pointers with a
specified address space. If the option is set to false, then reports from the
specific x86 address spaces 256, 257 and 258 are still suppressed, but null
dereferences from other address spaces are reported.

I think it is better to mention "(the default value)" immediately when you describe it.

// 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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// 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
// 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=common,x86-nosuppress %s
// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,alpha.core -std=gnu99 -verify=common,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=common,other-nosuppress %s
// RUN: %clang_analyze_cc1 -triple arm-pc-linux-gnu -analyzer-checker=core,alpha.core -std=gnu99 -verify=common,other-suppress %s

The -verify argument can accept multiple comma-separated labels and this can be used to simplify the code in cases where the same warning is emitted in many run lines. For example if you add the same string (e.g. common as in the suggested edit), you can write common-warning {{....}} instead of separately listing each of the four different labels.

Comment on lines 2947 to 2950

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
If the analyzer option ``suppress-all-address-spaces`` is set to true (the
default value), then this checker never reports dereference of pointers with a
specified address space. If the option is set to false, then reports from the
specific x86 address spaces 256, 257 and 258 are still suppressed, but fixed
address dereferences from other address spaces are reported.

This is the same paragraph that I suggested for the NullDereference checker.

true)
ANALYZER_OPTION(
bool, ShouldSuppressAddressSpaces, "suppress-all-address-spaces",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this analyzer option is misleading: the natural guess is that it makes the analyzer ignore the address space annotations -- and it's completely counter-intuitive that it suppresses certain results that come from two particular checkers. Of course the attached documentation describes its meaning, but I don't think that's enough (especially considering that these option docs are currently very obscure -- e.g. they don't appear on the webpage.

Note that this name was already misleading when it belonged to just a checker option, but moving it into the global namespace exacerbates the problem.

I know that it's difficult to find a more accurate name, but perhaps something like ignore-deref-from-all-address-spaces could work.

@steakhal What do you think about this?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that "ignore-all-address-spaces" would be really problematic but "suppress" is somehow related to eliminate reporting of specific errors (or path suppression). Probably "suppress-dereferences-from-any-address-space" is better.

@balazske

Labels