@@ -25,18 +25,22 @@ using namespace clang;
25
25
using namespace ento ;
26
26
27
27
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
+
28
40
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,
40
44
CheckerContext &C) const ;
41
45
42
46
bool suppressReport (CheckerContext &C, const Expr *E) const ;
@@ -52,13 +56,23 @@ class DereferenceChecker
52
56
const LocationContext *LCtx,
53
57
bool loadedFrom = false );
54
58
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" ; }
62
76
};
63
77
} // end anonymous namespace
64
78
@@ -158,115 +172,87 @@ static bool isDeclRefExprToReference(const Expr *E) {
158
172
return false ;
159
173
}
160
174
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.
179
182
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 ()) {
187
185
C.addSink ();
188
186
return ;
189
187
}
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
+ }
205
189
206
190
// Generate an error node.
207
191
ExplodedNode *N = C.generateErrorNode (State);
208
192
if (!N)
209
193
return ;
210
194
211
- SmallString<100 > buf ;
212
- llvm::raw_svector_ostream os (buf );
195
+ SmallString<100 > Buf ;
196
+ llvm::raw_svector_ostream Out (Buf );
213
197
214
198
SmallVector<SourceRange, 2 > Ranges;
215
199
216
200
switch (S->getStmtClass ()) {
217
201
case Stmt::ArraySubscriptExprClass: {
218
- os << " Array access" ;
202
+ Out << " Array access" ;
219
203
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 () ;
223
207
break ;
224
208
}
225
209
case Stmt::ArraySectionExprClass: {
226
- os << " Array access" ;
210
+ Out << " Array access" ;
227
211
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 () ;
231
215
break ;
232
216
}
233
217
case Stmt::UnaryOperatorClass: {
234
- os << BT-> getDescription ();
218
+ Out << BT. getDescription ();
235
219
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 );
238
222
break ;
239
223
}
240
224
case Stmt::MemberExprClass: {
241
225
const MemberExpr *M = cast<MemberExpr>(S);
242
226
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 );
246
231
}
247
232
break ;
248
233
}
249
234
case Stmt::ObjCIvarRefExprClass: {
250
235
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 );
254
240
break ;
255
241
}
256
242
default :
257
243
break ;
258
244
}
259
245
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);
262
248
263
- bugreporter::trackExpressionValue (N, bugreporter::getDerefExpr (S), *report );
249
+ bugreporter::trackExpressionValue (N, bugreporter::getDerefExpr (S), *BR );
264
250
265
251
for (SmallVectorImpl<SourceRange>::iterator
266
252
I = Ranges.begin (), E = Ranges.end (); I!=E; ++I)
267
- report ->addRange (*I);
253
+ BR ->addRange (*I);
268
254
269
- C.emitReport (std::move (report ));
255
+ C.emitReport (std::move (BR ));
270
256
}
271
257
272
258
void DereferenceChecker::checkLocation (SVal l, bool isLoad, const Stmt* S,
@@ -275,7 +261,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
275
261
if (l.isUndef ()) {
276
262
const Expr *DerefExpr = getDereferenceExpr (S);
277
263
if (!suppressReport (C, DerefExpr))
278
- reportBug (DerefKind::UndefinedPointerValue , C.getState (), DerefExpr, C);
264
+ reportBug (UndefBug , C.getState (), DerefExpr, C);
279
265
return ;
280
266
}
281
267
@@ -296,7 +282,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
296
282
// we call an "explicit" null dereference.
297
283
const Expr *expr = getDereferenceExpr (S);
298
284
if (!suppressReport (C, expr)) {
299
- reportBug (DerefKind::NullPointer , nullState, expr, C);
285
+ reportBug (NullBug , nullState, expr, C);
300
286
return ;
301
287
}
302
288
}
@@ -314,7 +300,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
314
300
if (location.isConstant ()) {
315
301
const Expr *DerefExpr = getDereferenceExpr (S, isLoad);
316
302
if (!suppressReport (C, DerefExpr))
317
- reportBug (DerefKind::FixedAddress , notNullState, DerefExpr, C);
303
+ reportBug (FixedAddressBug , notNullState, DerefExpr, C);
318
304
return ;
319
305
}
320
306
@@ -330,7 +316,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
330
316
331
317
// One should never write to label addresses.
332
318
if (auto Label = L.getAs <loc::GotoLabel>()) {
333
- reportBug (DerefKind::AddressOfLabel , C.getState (), S, C);
319
+ reportBug (LabelBug , C.getState (), S, C);
334
320
return ;
335
321
}
336
322
@@ -351,7 +337,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
351
337
if (!StNonNull) {
352
338
const Expr *expr = getDereferenceExpr (S, /* IsBind=*/ true );
353
339
if (!suppressReport (C, expr)) {
354
- reportBug (DerefKind::NullPointer , StNull, expr, C);
340
+ reportBug (NullBug , StNull, expr, C);
355
341
return ;
356
342
}
357
343
}
@@ -369,7 +355,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
369
355
if (V.isConstant ()) {
370
356
const Expr *DerefExpr = getDereferenceExpr (S, true );
371
357
if (!suppressReport (C, DerefExpr))
372
- reportBug (DerefKind::FixedAddress , State, DerefExpr, C);
358
+ reportBug (FixedAddressBug , State, DerefExpr, C);
373
359
return ;
374
360
}
375
361
@@ -392,38 +378,16 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
392
378
C.addTransition (State, this );
393
379
}
394
380
395
- void ento::registerDereferenceModeling (CheckerManager &Mgr) {
396
- Mgr.registerChecker <DereferenceChecker>();
397
- }
398
-
399
- bool ento::shouldRegisterDereferenceModeling (const CheckerManager &) {
400
- return true ;
401
- }
402
-
403
381
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);
415
383
}
416
384
417
385
bool ento::shouldRegisterNullDereferenceChecker (const CheckerManager &) {
418
386
return true ;
419
387
}
420
388
421
389
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);
427
391
}
428
392
429
393
bool ento::shouldRegisterFixedAddressDereferenceChecker (
0 commit comments