Skip to content

Commit bd2b7eb

Browse files
authored
[analyzer] Conversion to CheckerFamily: DereferenceChecker (#150442)
This commit converts the class DereferenceChecker to the checker family framework and simplifies some parts of the implementation. This commit is almost NFC, the only technically "functional" change is that it removes the hidden modeling checker `DereferenceModeling` which was only relevant as an implementation detail of the old checker registration procedure.
1 parent 98ec927 commit bd2b7eb

File tree

4 files changed

+81
-125
lines changed

4 files changed

+81
-125
lines changed

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

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,21 +206,15 @@ def CallAndMessageChecker : Checker<"CallAndMessage">,
206206
Documentation<HasDocumentation>,
207207
Dependencies<[CallAndMessageModeling]>;
208208

209-
def DereferenceModeling : Checker<"DereferenceModeling">,
210-
HelpText<"General support for dereference related checkers">,
211-
Documentation<NotDocumented>,
212-
Hidden;
213-
214209
def FixedAddressDereferenceChecker
215210
: Checker<"FixedAddressDereference">,
216211
HelpText<"Check for dereferences of fixed addresses">,
217-
Documentation<HasDocumentation>,
218-
Dependencies<[DereferenceModeling]>;
212+
Documentation<HasDocumentation>;
219213

220-
def NullDereferenceChecker : Checker<"NullDereference">,
221-
HelpText<"Check for dereferences of null pointers">,
222-
Documentation<HasDocumentation>,
223-
Dependencies<[DereferenceModeling]>;
214+
def NullDereferenceChecker
215+
: Checker<"NullDereference">,
216+
HelpText<"Check for dereferences of null pointers">,
217+
Documentation<HasDocumentation>;
224218

225219
def NonNullParamChecker : Checker<"NonNullParamChecker">,
226220
HelpText<"Check for null pointers passed as arguments to a function whose "

clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp

Lines changed: 76 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,22 @@ using namespace clang;
2525
using namespace ento;
2626

2727
namespace {
28+
29+
class DerefBugType : public BugType {
30+
StringRef ArrayMsg, FieldMsg;
31+
32+
public:
33+
DerefBugType(CheckerFrontend *FE, StringRef Desc, const char *AMsg,
34+
const char *FMsg = nullptr)
35+
: BugType(FE, Desc), ArrayMsg(AMsg), FieldMsg(FMsg ? FMsg : AMsg) {}
36+
StringRef getArrayMsg() const { return ArrayMsg; }
37+
StringRef getFieldMsg() const { return FieldMsg; }
38+
};
39+
2840
class DereferenceChecker
29-
: public Checker< check::Location,
30-
check::Bind,
31-
EventDispatcher<ImplicitNullDerefEvent> > {
32-
enum DerefKind {
33-
NullPointer,
34-
UndefinedPointerValue,
35-
AddressOfLabel,
36-
FixedAddress,
37-
};
38-
39-
void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S,
41+
: public CheckerFamily<check::Location, check::Bind,
42+
EventDispatcher<ImplicitNullDerefEvent>> {
43+
void reportBug(const DerefBugType &BT, ProgramStateRef State, const Stmt *S,
4044
CheckerContext &C) const;
4145

4246
bool suppressReport(CheckerContext &C, const Expr *E) const;
@@ -52,13 +56,23 @@ class DereferenceChecker
5256
const LocationContext *LCtx,
5357
bool loadedFrom = false);
5458

55-
bool CheckNullDereference = false;
56-
bool CheckFixedDereference = false;
57-
58-
std::unique_ptr<BugType> BT_Null;
59-
std::unique_ptr<BugType> BT_Undef;
60-
std::unique_ptr<BugType> BT_Label;
61-
std::unique_ptr<BugType> BT_FixedAddress;
59+
CheckerFrontend NullDerefChecker, FixedDerefChecker;
60+
const DerefBugType NullBug{&NullDerefChecker, "Dereference of null pointer",
61+
"a null pointer dereference",
62+
"a dereference of a null pointer"};
63+
const DerefBugType UndefBug{&NullDerefChecker,
64+
"Dereference of undefined pointer value",
65+
"an undefined pointer dereference",
66+
"a dereference of an undefined pointer value"};
67+
const DerefBugType LabelBug{&NullDerefChecker,
68+
"Dereference of the address of a label",
69+
"an undefined pointer dereference",
70+
"a dereference of an address of a label"};
71+
const DerefBugType FixedAddressBug{&FixedDerefChecker,
72+
"Dereference of a fixed address",
73+
"a dereference of a fixed address"};
74+
75+
StringRef getDebugTag() const override { return "DereferenceChecker"; }
6276
};
6377
} // end anonymous namespace
6478

@@ -158,115 +172,87 @@ static bool isDeclRefExprToReference(const Expr *E) {
158172
return false;
159173
}
160174

161-
void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State,
162-
const Stmt *S, CheckerContext &C) const {
163-
const BugType *BT = nullptr;
164-
llvm::StringRef DerefStr1;
165-
llvm::StringRef DerefStr2;
166-
switch (K) {
167-
case DerefKind::NullPointer:
168-
if (!CheckNullDereference) {
169-
C.addSink();
170-
return;
171-
}
172-
BT = BT_Null.get();
173-
DerefStr1 = " results in a null pointer dereference";
174-
DerefStr2 = " results in a dereference of a null pointer";
175-
break;
176-
case DerefKind::UndefinedPointerValue:
177-
if (!CheckNullDereference) {
178-
C.addSink();
175+
void DereferenceChecker::reportBug(const DerefBugType &BT,
176+
ProgramStateRef State, const Stmt *S,
177+
CheckerContext &C) const {
178+
if (&BT == &FixedAddressBug) {
179+
if (!FixedDerefChecker.isEnabled())
180+
// Deliberately don't add a sink node if check is disabled.
181+
// This situation may be valid in special cases.
179182
return;
180-
}
181-
BT = BT_Undef.get();
182-
DerefStr1 = " results in an undefined pointer dereference";
183-
DerefStr2 = " results in a dereference of an undefined pointer value";
184-
break;
185-
case DerefKind::AddressOfLabel:
186-
if (!CheckNullDereference) {
183+
} else {
184+
if (!NullDerefChecker.isEnabled()) {
187185
C.addSink();
188186
return;
189187
}
190-
BT = BT_Label.get();
191-
DerefStr1 = " results in an undefined pointer dereference";
192-
DerefStr2 = " results in a dereference of an address of a label";
193-
break;
194-
case DerefKind::FixedAddress:
195-
// Deliberately don't add a sink node if check is disabled.
196-
// This situation may be valid in special cases.
197-
if (!CheckFixedDereference)
198-
return;
199-
200-
BT = BT_FixedAddress.get();
201-
DerefStr1 = " results in a dereference of a fixed address";
202-
DerefStr2 = " results in a dereference of a fixed address";
203-
break;
204-
};
188+
}
205189

206190
// Generate an error node.
207191
ExplodedNode *N = C.generateErrorNode(State);
208192
if (!N)
209193
return;
210194

211-
SmallString<100> buf;
212-
llvm::raw_svector_ostream os(buf);
195+
SmallString<100> Buf;
196+
llvm::raw_svector_ostream Out(Buf);
213197

214198
SmallVector<SourceRange, 2> Ranges;
215199

216200
switch (S->getStmtClass()) {
217201
case Stmt::ArraySubscriptExprClass: {
218-
os << "Array access";
202+
Out << "Array access";
219203
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
220-
AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
221-
State.get(), N->getLocationContext());
222-
os << DerefStr1;
204+
AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(),
205+
N->getLocationContext());
206+
Out << " results in " << BT.getArrayMsg();
223207
break;
224208
}
225209
case Stmt::ArraySectionExprClass: {
226-
os << "Array access";
210+
Out << "Array access";
227211
const ArraySectionExpr *AE = cast<ArraySectionExpr>(S);
228-
AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
229-
State.get(), N->getLocationContext());
230-
os << DerefStr1;
212+
AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(),
213+
N->getLocationContext());
214+
Out << " results in " << BT.getArrayMsg();
231215
break;
232216
}
233217
case Stmt::UnaryOperatorClass: {
234-
os << BT->getDescription();
218+
Out << BT.getDescription();
235219
const UnaryOperator *U = cast<UnaryOperator>(S);
236-
AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
237-
State.get(), N->getLocationContext(), true);
220+
AddDerefSource(Out, Ranges, U->getSubExpr()->IgnoreParens(), State.get(),
221+
N->getLocationContext(), true);
238222
break;
239223
}
240224
case Stmt::MemberExprClass: {
241225
const MemberExpr *M = cast<MemberExpr>(S);
242226
if (M->isArrow() || isDeclRefExprToReference(M->getBase())) {
243-
os << "Access to field '" << M->getMemberNameInfo() << "'" << DerefStr2;
244-
AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
245-
State.get(), N->getLocationContext(), true);
227+
Out << "Access to field '" << M->getMemberNameInfo() << "' results in "
228+
<< BT.getFieldMsg();
229+
AddDerefSource(Out, Ranges, M->getBase()->IgnoreParenCasts(), State.get(),
230+
N->getLocationContext(), true);
246231
}
247232
break;
248233
}
249234
case Stmt::ObjCIvarRefExprClass: {
250235
const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
251-
os << "Access to instance variable '" << *IV->getDecl() << "'" << DerefStr2;
252-
AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
253-
State.get(), N->getLocationContext(), true);
236+
Out << "Access to instance variable '" << *IV->getDecl() << "' results in "
237+
<< BT.getFieldMsg();
238+
AddDerefSource(Out, Ranges, IV->getBase()->IgnoreParenCasts(), State.get(),
239+
N->getLocationContext(), true);
254240
break;
255241
}
256242
default:
257243
break;
258244
}
259245

260-
auto report = std::make_unique<PathSensitiveBugReport>(
261-
*BT, buf.empty() ? BT->getDescription() : buf.str(), N);
246+
auto BR = std::make_unique<PathSensitiveBugReport>(
247+
BT, Buf.empty() ? BT.getDescription() : Buf.str(), N);
262248

263-
bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
249+
bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *BR);
264250

265251
for (SmallVectorImpl<SourceRange>::iterator
266252
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
267-
report->addRange(*I);
253+
BR->addRange(*I);
268254

269-
C.emitReport(std::move(report));
255+
C.emitReport(std::move(BR));
270256
}
271257

272258
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
@@ -275,7 +261,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
275261
if (l.isUndef()) {
276262
const Expr *DerefExpr = getDereferenceExpr(S);
277263
if (!suppressReport(C, DerefExpr))
278-
reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C);
264+
reportBug(UndefBug, C.getState(), DerefExpr, C);
279265
return;
280266
}
281267

@@ -296,7 +282,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
296282
// we call an "explicit" null dereference.
297283
const Expr *expr = getDereferenceExpr(S);
298284
if (!suppressReport(C, expr)) {
299-
reportBug(DerefKind::NullPointer, nullState, expr, C);
285+
reportBug(NullBug, nullState, expr, C);
300286
return;
301287
}
302288
}
@@ -314,7 +300,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
314300
if (location.isConstant()) {
315301
const Expr *DerefExpr = getDereferenceExpr(S, isLoad);
316302
if (!suppressReport(C, DerefExpr))
317-
reportBug(DerefKind::FixedAddress, notNullState, DerefExpr, C);
303+
reportBug(FixedAddressBug, notNullState, DerefExpr, C);
318304
return;
319305
}
320306

@@ -330,7 +316,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
330316

331317
// One should never write to label addresses.
332318
if (auto Label = L.getAs<loc::GotoLabel>()) {
333-
reportBug(DerefKind::AddressOfLabel, C.getState(), S, C);
319+
reportBug(LabelBug, C.getState(), S, C);
334320
return;
335321
}
336322

@@ -351,7 +337,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
351337
if (!StNonNull) {
352338
const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
353339
if (!suppressReport(C, expr)) {
354-
reportBug(DerefKind::NullPointer, StNull, expr, C);
340+
reportBug(NullBug, StNull, expr, C);
355341
return;
356342
}
357343
}
@@ -369,7 +355,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
369355
if (V.isConstant()) {
370356
const Expr *DerefExpr = getDereferenceExpr(S, true);
371357
if (!suppressReport(C, DerefExpr))
372-
reportBug(DerefKind::FixedAddress, State, DerefExpr, C);
358+
reportBug(FixedAddressBug, State, DerefExpr, C);
373359
return;
374360
}
375361

@@ -392,38 +378,16 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
392378
C.addTransition(State, this);
393379
}
394380

395-
void ento::registerDereferenceModeling(CheckerManager &Mgr) {
396-
Mgr.registerChecker<DereferenceChecker>();
397-
}
398-
399-
bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) {
400-
return true;
401-
}
402-
403381
void ento::registerNullDereferenceChecker(CheckerManager &Mgr) {
404-
auto *Chk = Mgr.getChecker<DereferenceChecker>();
405-
Chk->CheckNullDereference = true;
406-
Chk->BT_Null.reset(new BugType(Mgr.getCurrentCheckerName(),
407-
"Dereference of null pointer",
408-
categories::LogicError));
409-
Chk->BT_Undef.reset(new BugType(Mgr.getCurrentCheckerName(),
410-
"Dereference of undefined pointer value",
411-
categories::LogicError));
412-
Chk->BT_Label.reset(new BugType(Mgr.getCurrentCheckerName(),
413-
"Dereference of the address of a label",
414-
categories::LogicError));
382+
Mgr.getChecker<DereferenceChecker>()->NullDerefChecker.enable(Mgr);
415383
}
416384

417385
bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) {
418386
return true;
419387
}
420388

421389
void ento::registerFixedAddressDereferenceChecker(CheckerManager &Mgr) {
422-
auto *Chk = Mgr.getChecker<DereferenceChecker>();
423-
Chk->CheckFixedDereference = true;
424-
Chk->BT_FixedAddress.reset(new BugType(Mgr.getCurrentCheckerName(),
425-
"Dereference of a fixed address",
426-
categories::LogicError));
390+
Mgr.getChecker<DereferenceChecker>()->FixedDerefChecker.enable(Mgr);
427391
}
428392

429393
bool ento::shouldRegisterFixedAddressDereferenceChecker(

clang/test/Analysis/analyzer-enabled-checkers.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
// CHECK-NEXT: core.BitwiseShift
1515
// CHECK-NEXT: core.CallAndMessageModeling
1616
// CHECK-NEXT: core.CallAndMessage
17-
// CHECK-NEXT: core.DereferenceModeling
1817
// CHECK-NEXT: core.DivideZero
1918
// CHECK-NEXT: core.DynamicTypePropagation
2019
// CHECK-NEXT: core.FixedAddressDereference

clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
// CHECK-NEXT: core.BitwiseShift
2323
// CHECK-NEXT: core.CallAndMessageModeling
2424
// CHECK-NEXT: core.CallAndMessage
25-
// CHECK-NEXT: core.DereferenceModeling
2625
// CHECK-NEXT: core.DivideZero
2726
// CHECK-NEXT: core.DynamicTypePropagation
2827
// CHECK-NEXT: core.FixedAddressDereference

0 commit comments

Comments
 (0)