Skip to content

Commit da7403e

Browse files
authored
[clang][analyzer] Add checker 'alpha.core.FixedAddressDereference' (#127191)
1 parent 1119b72 commit da7403e

File tree

9 files changed

+347
-43
lines changed

9 files changed

+347
-43
lines changed

clang/docs/analyzer/checkers.rst

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,19 +118,6 @@ core.NullDereference (C, C++, ObjC)
118118
"""""""""""""""""""""""""""""""""""
119119
Check for dereferences of null pointers.
120120

121-
This checker specifically does
122-
not report null pointer dereferences for x86 and x86-64 targets when the
123-
address space is 256 (x86 GS Segment), 257 (x86 FS Segment), or 258 (x86 SS
124-
segment). See `X86/X86-64 Language Extensions
125-
<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__
126-
for reference.
127-
128-
The ``SuppressAddressSpaces`` option suppresses
129-
warnings for null dereferences of all pointers with address spaces. You can
130-
disable this behavior with the option
131-
``-analyzer-config core.NullDereference:SuppressAddressSpaces=false``.
132-
*Defaults to true*.
133-
134121
.. code-block:: objc
135122
136123
// C
@@ -170,6 +157,19 @@ disable this behavior with the option
170157
obj->x = 1; // warn
171158
}
172159
160+
Null pointer dereferences of pointers with address spaces are not always defined
161+
as error. Specifically on x86/x86-64 target if the pointer address space is
162+
256 (x86 GS Segment), 257 (x86 FS Segment), or 258 (x86 SS Segment), a null
163+
dereference is not defined as error. See `X86/X86-64 Language Extensions
164+
<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__
165+
for reference.
166+
167+
If the analyzer option ``suppress-dereferences-from-any-address-space`` is set
168+
to true (the default value), then this checker never reports dereference of
169+
pointers with a specified address space. If the option is set to false, then
170+
reports from the specific x86 address spaces 256, 257 and 258 are still
171+
suppressed, but null dereferences from other address spaces are reported.
172+
173173
.. _core-StackAddressEscape:
174174
175175
core.StackAddressEscape (C)
@@ -2919,6 +2919,41 @@ Check for assignment of a fixed address to a pointer.
29192919
p = (int *) 0x10000; // warn
29202920
}
29212921
2922+
.. _alpha-core-FixedAddressDereference:
2923+
2924+
alpha.core.FixedAddressDereference (C, C++, ObjC)
2925+
"""""""""""""""""""""""""""""""""""""""""""""""""
2926+
Check for dereferences of fixed addresses.
2927+
2928+
A pointer contains a fixed address if it was set to a hard-coded value or it
2929+
becomes otherwise obvious that at that point it can have only a single specific
2930+
value.
2931+
2932+
.. code-block:: c
2933+
2934+
void test1() {
2935+
int *p = (int *)0x020;
2936+
int x = p[0]; // warn
2937+
}
2938+
2939+
void test2(int *p) {
2940+
if (p == (int *)-1)
2941+
*p = 0; // warn
2942+
}
2943+
2944+
void test3() {
2945+
int (*p_function)(char, char);
2946+
p_function = (int (*)(char, char))0x04080;
2947+
int x = (*p_function)('x', 'y'); // NO warning yet at functon pointer calls
2948+
}
2949+
2950+
If the analyzer option ``suppress-dereferences-from-any-address-space`` is set
2951+
to true (the default value), then this checker never reports dereference of
2952+
pointers with a specified address space. If the option is set to false, then
2953+
reports from the specific x86 address spaces 256, 257 and 258 are still
2954+
suppressed, but fixed address dereferences from other address spaces are
2955+
reported.
2956+
29222957
.. _alpha-core-PointerArithm:
29232958
29242959
alpha.core.PointerArithm (C)

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,6 @@ def DereferenceModeling : Checker<"DereferenceModeling">,
213213

214214
def NullDereferenceChecker : Checker<"NullDereference">,
215215
HelpText<"Check for dereferences of null pointers">,
216-
CheckerOptions<[
217-
CmdLineOption<Boolean,
218-
"SuppressAddressSpaces",
219-
"Suppresses warning when pointer dereferences an address space",
220-
"true",
221-
Released>
222-
]>,
223216
Documentation<HasDocumentation>,
224217
Dependencies<[DereferenceModeling]>;
225218

@@ -285,6 +278,12 @@ def FixedAddressChecker : Checker<"FixedAddr">,
285278
HelpText<"Check for assignment of a fixed address to a pointer">,
286279
Documentation<HasDocumentation>;
287280

281+
def FixedAddressDereferenceChecker
282+
: Checker<"FixedAddressDereference">,
283+
HelpText<"Check for dereferences of fixed addresses">,
284+
Documentation<HasDocumentation>,
285+
Dependencies<[DereferenceModeling]>;
286+
288287
def PointerArithChecker : Checker<"PointerArithm">,
289288
HelpText<"Check for pointer arithmetic on locations other than array "
290289
"elements">,

clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,19 @@ ANALYZER_OPTION(
395395
"flex\" won't be analyzed.",
396396
true)
397397

398+
ANALYZER_OPTION(
399+
bool, ShouldSuppressAddressSpaceDereferences, "suppress-dereferences-from-any-address-space",
400+
"The analyzer does not report dereferences on memory that use "
401+
"address space #256, #257, and #258. Those address spaces are used when "
402+
"dereferencing address spaces relative to the GS, FS, and SS segments on "
403+
"x86/x86-64 targets. Dereferencing a null pointer in these address spaces "
404+
"is not defined as an error. All other null dereferences in other address "
405+
"spaces are defined as an error unless explicitly defined. "
406+
"When this option is turned on, the special behavior of address spaces "
407+
"#256, #257, #258 is extended to all pointers with address spaces and on "
408+
"any target.",
409+
true)
410+
398411
//===----------------------------------------------------------------------===//
399412
// Unsigned analyzer options.
400413
//===----------------------------------------------------------------------===//

clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ class DereferenceChecker
3131
: public Checker< check::Location,
3232
check::Bind,
3333
EventDispatcher<ImplicitNullDerefEvent> > {
34-
enum DerefKind { NullPointer, UndefinedPointerValue, AddressOfLabel };
34+
enum DerefKind {
35+
NullPointer,
36+
UndefinedPointerValue,
37+
AddressOfLabel,
38+
FixedAddress,
39+
};
3540

3641
void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S,
3742
CheckerContext &C) const;
@@ -49,13 +54,13 @@ class DereferenceChecker
4954
const LocationContext *LCtx,
5055
bool loadedFrom = false);
5156

52-
bool SuppressAddressSpaces = false;
53-
5457
bool CheckNullDereference = false;
58+
bool CheckFixedDereference = false;
5559

5660
std::unique_ptr<BugType> BT_Null;
5761
std::unique_ptr<BugType> BT_Undef;
5862
std::unique_ptr<BugType> BT_Label;
63+
std::unique_ptr<BugType> BT_FixedAddress;
5964
};
6065
} // end anonymous namespace
6166

@@ -130,7 +135,9 @@ bool DereferenceChecker::suppressReport(CheckerContext &C,
130135
QualType Ty = E->getType();
131136
if (!Ty.hasAddressSpace())
132137
return false;
133-
if (SuppressAddressSpaces)
138+
if (C.getAnalysisManager()
139+
.getAnalyzerOptions()
140+
.ShouldSuppressAddressSpaceDereferences)
134141
return true;
135142

136143
const llvm::Triple::ArchType Arch =
@@ -155,30 +162,47 @@ static bool isDeclRefExprToReference(const Expr *E) {
155162

156163
void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State,
157164
const Stmt *S, CheckerContext &C) const {
158-
if (!CheckNullDereference) {
159-
C.addSink();
160-
return;
161-
}
162-
163165
const BugType *BT = nullptr;
164166
llvm::StringRef DerefStr1;
165167
llvm::StringRef DerefStr2;
166168
switch (K) {
167169
case DerefKind::NullPointer:
170+
if (!CheckNullDereference) {
171+
C.addSink();
172+
return;
173+
}
168174
BT = BT_Null.get();
169175
DerefStr1 = " results in a null pointer dereference";
170176
DerefStr2 = " results in a dereference of a null pointer";
171177
break;
172178
case DerefKind::UndefinedPointerValue:
179+
if (!CheckNullDereference) {
180+
C.addSink();
181+
return;
182+
}
173183
BT = BT_Undef.get();
174184
DerefStr1 = " results in an undefined pointer dereference";
175185
DerefStr2 = " results in a dereference of an undefined pointer value";
176186
break;
177187
case DerefKind::AddressOfLabel:
188+
if (!CheckNullDereference) {
189+
C.addSink();
190+
return;
191+
}
178192
BT = BT_Label.get();
179193
DerefStr1 = " results in an undefined pointer dereference";
180194
DerefStr2 = " results in a dereference of an address of a label";
181195
break;
196+
case DerefKind::FixedAddress:
197+
// Deliberately don't add a sink node if check is disabled.
198+
// This situation may be valid in special cases.
199+
if (!CheckFixedDereference)
200+
return;
201+
202+
BT = BT_FixedAddress.get();
203+
DerefStr1 = " results in a dereference of a fixed address";
204+
DerefStr2 = " results in a dereference of a fixed address";
205+
break;
182206
};
183207

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

316+
if (location.isConstant()) {
317+
const Expr *DerefExpr = getDereferenceExpr(S, isLoad);
318+
if (!suppressReport(C, DerefExpr))
319+
reportBug(DerefKind::FixedAddress, notNullState, DerefExpr, C);
320+
return;
321+
}
322+
292323
// From this point forward, we know that the location is not null.
293324
C.addTransition(notNullState);
294325
}
@@ -337,6 +368,13 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
337368
}
338369
}
339370

371+
if (V.isConstant()) {
372+
const Expr *DerefExpr = getDereferenceExpr(S, true);
373+
if (!suppressReport(C, DerefExpr))
374+
reportBug(DerefKind::FixedAddress, State, DerefExpr, C);
375+
return;
376+
}
377+
340378
// Unlike a regular null dereference, initializing a reference with a
341379
// dereferenced null pointer does not actually cause a runtime exception in
342380
// Clang's implementation of references.
@@ -367,8 +405,6 @@ bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) {
367405
void ento::registerNullDereferenceChecker(CheckerManager &Mgr) {
368406
auto *Chk = Mgr.getChecker<DereferenceChecker>();
369407
Chk->CheckNullDereference = true;
370-
Chk->SuppressAddressSpaces = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
371-
Mgr.getCurrentCheckerName(), "SuppressAddressSpaces");
372408
Chk->BT_Null.reset(new BugType(Mgr.getCurrentCheckerName(),
373409
"Dereference of null pointer",
374410
categories::LogicError));
@@ -383,3 +419,16 @@ void ento::registerNullDereferenceChecker(CheckerManager &Mgr) {
383419
bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) {
384420
return true;
385421
}
422+
423+
void ento::registerFixedAddressDereferenceChecker(CheckerManager &Mgr) {
424+
auto *Chk = Mgr.getChecker<DereferenceChecker>();
425+
Chk->CheckFixedDereference = true;
426+
Chk->BT_FixedAddress.reset(new BugType(Mgr.getCurrentCheckerName(),
427+
"Dereference of a fixed address",
428+
categories::LogicError));
429+
}
430+
431+
bool ento::shouldRegisterFixedAddressDereferenceChecker(
432+
const CheckerManager &) {
433+
return true;
434+
}

clang/test/Analysis/analyzer-config.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
// CHECK-NEXT: core.CallAndMessage:NilReceiver = true
3838
// CHECK-NEXT: core.CallAndMessage:ParameterCount = true
3939
// CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
40-
// CHECK-NEXT: core.NullDereference:SuppressAddressSpaces = true
4140
// CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
4241
// CHECK-NEXT: cplusplus.SmartPtrModeling:ModelSmartPtrDereference = false
4342
// CHECK-NEXT: crosscheck-with-z3 = false
@@ -126,6 +125,7 @@
126125
// CHECK-NEXT: stable-report-filename = false
127126
// CHECK-NEXT: support-symbolic-integer-casts = false
128127
// CHECK-NEXT: suppress-c++-stdlib = true
128+
// CHECK-NEXT: suppress-dereferences-from-any-address-space = true
129129
// CHECK-NEXT: suppress-inlined-defensive-checks = true
130130
// CHECK-NEXT: suppress-null-return-paths = true
131131
// CHECK-NEXT: track-conditions = true

clang/test/Analysis/cast-value-notes.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
//
55
// RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \
66
// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
7-
// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=false\
7+
// RUN: -analyzer-config suppress-dereferences-from-any-address-space=false\
88
// RUN: -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK
99
//
1010
// RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \
1111
// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
12-
// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=true\
12+
// RUN: -analyzer-config suppress-dereferences-from-any-address-space=true\
1313
// RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK
1414
//
1515
// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \
@@ -18,12 +18,12 @@
1818
//
1919
// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \
2020
// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
21-
// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=true\
21+
// RUN: -analyzer-config suppress-dereferences-from-any-address-space=true\
2222
// RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK-SUPPRESSED
2323
//
2424
// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \
2525
// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
26-
// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=false\
26+
// RUN: -analyzer-config suppress-dereferences-from-any-address-space=false\
2727
// RUN: -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK
2828
//
2929
// RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \
@@ -32,12 +32,12 @@
3232
//
3333
// RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \
3434
// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
35-
// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=false\
35+
// RUN: -analyzer-config suppress-dereferences-from-any-address-space=false\
3636
// RUN: -analyzer-output=text -verify -DMIPS %s 2>&1
3737
//
3838
// RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \
3939
// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
40-
// RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=true\
40+
// RUN: -analyzer-config suppress-dereferences-from-any-address-space=true\
4141
// RUN: -analyzer-output=text -verify -DMIPS_SUPPRESSED %s
4242

4343
#include "Inputs/llvm.h"

0 commit comments

Comments
 (0)