@@ -25,18 +25,22 @@ using namespace clang;
2525using namespace ento ;
2626
2727namespace {
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+
2840class 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
272256void 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-
403379void 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
417383bool ento::shouldRegisterNullDereferenceChecker (const CheckerManager &) {
418384 return true ;
419385}
420386
421387void 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
429391bool ento::shouldRegisterFixedAddressDereferenceChecker (
0 commit comments