@@ -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 *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+
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,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
272258void 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-
403381void 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
417385bool ento::shouldRegisterNullDereferenceChecker (const CheckerManager &) {
418386 return true ;
419387}
420388
421389void 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
429393bool ento::shouldRegisterFixedAddressDereferenceChecker (
0 commit comments