Skip to content

Commit 4403a6e

Browse files
committed
[analyzer] Conversion to CheckerFamily: DereferenceChecker
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 deede2b commit 4403a6e

File tree

4 files changed

+79
-125
lines changed

4 files changed

+79
-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: 74 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 *RMsg,
34+
const char *FMsg = nullptr)
35+
: BugType(FE, Desc), ArrayMsg(RMsg), FieldMsg(FMsg ? FMsg : RMsg) {}
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,85 @@ 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())
179180
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) {
181+
} else {
182+
if (!NullDerefChecker.isEnabled()) {
187183
C.addSink();
188184
return;
189185
}
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-
};
186+
}
205187

206188
// Generate an error node.
207189
ExplodedNode *N = C.generateErrorNode(State);
208190
if (!N)
209191
return;
210192

211-
SmallString<100> buf;
212-
llvm::raw_svector_ostream os(buf);
193+
SmallString<100> Buf;
194+
llvm::raw_svector_ostream Out(Buf);
213195

214196
SmallVector<SourceRange, 2> Ranges;
215197

216198
switch (S->getStmtClass()) {
217199
case Stmt::ArraySubscriptExprClass: {
218-
os << "Array access";
200+
Out << "Array access";
219201
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
220-
AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
221-
State.get(), N->getLocationContext());
222-
os << DerefStr1;
202+
AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(),
203+
N->getLocationContext());
204+
Out << " results in " << BT.getArrayMsg();
223205
break;
224206
}
225207
case Stmt::ArraySectionExprClass: {
226-
os << "Array access";
208+
Out << "Array access";
227209
const ArraySectionExpr *AE = cast<ArraySectionExpr>(S);
228-
AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
229-
State.get(), N->getLocationContext());
230-
os << DerefStr1;
210+
AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(),
211+
N->getLocationContext());
212+
Out << " results in " << BT.getArrayMsg();
231213
break;
232214
}
233215
case Stmt::UnaryOperatorClass: {
234-
os << BT->getDescription();
216+
Out << BT.getDescription();
235217
const UnaryOperator *U = cast<UnaryOperator>(S);
236-
AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
237-
State.get(), N->getLocationContext(), true);
218+
AddDerefSource(Out, Ranges, U->getSubExpr()->IgnoreParens(), State.get(),
219+
N->getLocationContext(), true);
238220
break;
239221
}
240222
case Stmt::MemberExprClass: {
241223
const MemberExpr *M = cast<MemberExpr>(S);
242224
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);
225+
Out << "Access to field '" << M->getMemberNameInfo() << "' results in "
226+
<< BT.getFieldMsg();
227+
AddDerefSource(Out, Ranges, M->getBase()->IgnoreParenCasts(), State.get(),
228+
N->getLocationContext(), true);
246229
}
247230
break;
248231
}
249232
case Stmt::ObjCIvarRefExprClass: {
250233
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);
234+
Out << "Access to instance variable '" << *IV->getDecl() << "' results in "
235+
<< BT.getFieldMsg();
236+
AddDerefSource(Out, Ranges, IV->getBase()->IgnoreParenCasts(), State.get(),
237+
N->getLocationContext(), true);
254238
break;
255239
}
256240
default:
257241
break;
258242
}
259243

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

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

265249
for (SmallVectorImpl<SourceRange>::iterator
266250
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
267-
report->addRange(*I);
251+
BR->addRange(*I);
268252

269-
C.emitReport(std::move(report));
253+
C.emitReport(std::move(BR));
270254
}
271255

272256
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
@@ -275,7 +259,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
275259
if (l.isUndef()) {
276260
const Expr *DerefExpr = getDereferenceExpr(S);
277261
if (!suppressReport(C, DerefExpr))
278-
reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C);
262+
reportBug(UndefBug, C.getState(), DerefExpr, C);
279263
return;
280264
}
281265

@@ -296,7 +280,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
296280
// we call an "explicit" null dereference.
297281
const Expr *expr = getDereferenceExpr(S);
298282
if (!suppressReport(C, expr)) {
299-
reportBug(DerefKind::NullPointer, nullState, expr, C);
283+
reportBug(NullBug, nullState, expr, C);
300284
return;
301285
}
302286
}
@@ -314,7 +298,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
314298
if (location.isConstant()) {
315299
const Expr *DerefExpr = getDereferenceExpr(S, isLoad);
316300
if (!suppressReport(C, DerefExpr))
317-
reportBug(DerefKind::FixedAddress, notNullState, DerefExpr, C);
301+
reportBug(FixedAddressBug, notNullState, DerefExpr, C);
318302
return;
319303
}
320304

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

331315
// One should never write to label addresses.
332316
if (auto Label = L.getAs<loc::GotoLabel>()) {
333-
reportBug(DerefKind::AddressOfLabel, C.getState(), S, C);
317+
reportBug(LabelBug, C.getState(), S, C);
334318
return;
335319
}
336320

@@ -351,7 +335,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
351335
if (!StNonNull) {
352336
const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
353337
if (!suppressReport(C, expr)) {
354-
reportBug(DerefKind::NullPointer, StNull, expr, C);
338+
reportBug(NullBug, StNull, expr, C);
355339
return;
356340
}
357341
}
@@ -369,7 +353,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
369353
if (V.isConstant()) {
370354
const Expr *DerefExpr = getDereferenceExpr(S, true);
371355
if (!suppressReport(C, DerefExpr))
372-
reportBug(DerefKind::FixedAddress, State, DerefExpr, C);
356+
reportBug(FixedAddressBug, State, DerefExpr, C);
373357
return;
374358
}
375359

@@ -392,38 +376,16 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
392376
C.addTransition(State, this);
393377
}
394378

395-
void ento::registerDereferenceModeling(CheckerManager &Mgr) {
396-
Mgr.registerChecker<DereferenceChecker>();
397-
}
398-
399-
bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) {
400-
return true;
401-
}
402-
403379
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));
380+
Mgr.getChecker<DereferenceChecker>()->NullDerefChecker.enable(Mgr);
415381
}
416382

417383
bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) {
418384
return true;
419385
}
420386

421387
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));
388+
Mgr.getChecker<DereferenceChecker>()->FixedDerefChecker.enable(Mgr);
427389
}
428390

429391
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)