1//== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines Checker, used to create and register checkers.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H
14#define LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H
15
16#include "clang/Analysis/ProgramPoint.h"
17#include "clang/Basic/LangOptions.h"
18#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
20#include "llvm/Support/Casting.h"
21
22namespace clang {
23namespace ento {
24 class BugReporter;
25
26namespace check {
27
28template <typename DECL>
29class ASTDecl {
30 template <typename CHECKER>
31 static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr,
32 BugReporter &BR) {
33 ((const CHECKER *)checker)->checkASTDecl(cast<DECL>(D), mgr, BR);
34 }
35
36 static bool _handlesDecl(const Decl *D) {
37 return isa<DECL>(D);
38 }
39public:
40 template <typename CHECKER>
41 static void _register(CHECKER *checker, CheckerManager &mgr) {
42 mgr._registerForDecl(checkfn: CheckerManager::CheckDeclFunc(checker,
43 _checkDecl<CHECKER>),
44 isForDeclFn: _handlesDecl);
45 }
46};
47
48class ASTCodeBody {
49 template <typename CHECKER>
50 static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr,
51 BugReporter &BR) {
52 ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR);
53 }
54
55public:
56 template <typename CHECKER>
57 static void _register(CHECKER *checker, CheckerManager &mgr) {
58 mgr._registerForBody(checkfn: CheckerManager::CheckDeclFunc(checker,
59 _checkBody<CHECKER>));
60 }
61};
62
63class EndOfTranslationUnit {
64 template <typename CHECKER>
65 static void _checkEndOfTranslationUnit(void *checker,
66 const TranslationUnitDecl *TU,
67 AnalysisManager& mgr,
68 BugReporter &BR) {
69 ((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR);
70 }
71
72public:
73 template <typename CHECKER>
74 static void _register(CHECKER *checker, CheckerManager &mgr){
75 mgr._registerForEndOfTranslationUnit(
76 checkfn: CheckerManager::CheckEndOfTranslationUnit(checker,
77 _checkEndOfTranslationUnit<CHECKER>));
78 }
79};
80
81template <typename STMT>
82class PreStmt {
83 template <typename CHECKER>
84 static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
85 ((const CHECKER *)checker)->checkPreStmt(cast<STMT>(S), C);
86 }
87
88 static bool _handlesStmt(const Stmt *S) {
89 return isa<STMT>(S);
90 }
91public:
92 template <typename CHECKER>
93 static void _register(CHECKER *checker, CheckerManager &mgr) {
94 mgr._registerForPreStmt(checkfn: CheckerManager::CheckStmtFunc(checker,
95 _checkStmt<CHECKER>),
96 isForStmtFn: _handlesStmt);
97 }
98};
99
100template <typename STMT>
101class PostStmt {
102 template <typename CHECKER>
103 static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
104 ((const CHECKER *)checker)->checkPostStmt(cast<STMT>(S), C);
105 }
106
107 static bool _handlesStmt(const Stmt *S) {
108 return isa<STMT>(S);
109 }
110public:
111 template <typename CHECKER>
112 static void _register(CHECKER *checker, CheckerManager &mgr) {
113 mgr._registerForPostStmt(checkfn: CheckerManager::CheckStmtFunc(checker,
114 _checkStmt<CHECKER>),
115 isForStmtFn: _handlesStmt);
116 }
117};
118
119class PreObjCMessage {
120 template <typename CHECKER>
121 static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
122 CheckerContext &C) {
123 ((const CHECKER *)checker)->checkPreObjCMessage(msg, C);
124 }
125
126public:
127 template <typename CHECKER>
128 static void _register(CHECKER *checker, CheckerManager &mgr) {
129 mgr._registerForPreObjCMessage(
130 checkfn: CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
131 }
132};
133
134class ObjCMessageNil {
135 template <typename CHECKER>
136 static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
137 CheckerContext &C) {
138 ((const CHECKER *)checker)->checkObjCMessageNil(msg, C);
139 }
140
141public:
142 template <typename CHECKER>
143 static void _register(CHECKER *checker, CheckerManager &mgr) {
144 mgr._registerForObjCMessageNil(
145 checkfn: CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
146 }
147};
148
149class PostObjCMessage {
150 template <typename CHECKER>
151 static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg,
152 CheckerContext &C) {
153 ((const CHECKER *)checker)->checkPostObjCMessage(msg, C);
154 }
155
156public:
157 template <typename CHECKER>
158 static void _register(CHECKER *checker, CheckerManager &mgr) {
159 mgr._registerForPostObjCMessage(
160 checkfn: CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>));
161 }
162};
163
164class PreCall {
165 template <typename CHECKER>
166 static void _checkCall(void *checker, const CallEvent &msg,
167 CheckerContext &C) {
168 ((const CHECKER *)checker)->checkPreCall(msg, C);
169 }
170
171public:
172 template <typename CHECKER>
173 static void _register(CHECKER *checker, CheckerManager &mgr) {
174 mgr._registerForPreCall(
175 checkfn: CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
176 }
177};
178
179class PostCall {
180 template <typename CHECKER>
181 static void _checkCall(void *checker, const CallEvent &msg,
182 CheckerContext &C) {
183 ((const CHECKER *)checker)->checkPostCall(msg, C);
184 }
185
186public:
187 template <typename CHECKER>
188 static void _register(CHECKER *checker, CheckerManager &mgr) {
189 mgr._registerForPostCall(
190 checkfn: CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
191 }
192};
193
194class Location {
195 template <typename CHECKER>
196 static void _checkLocation(void *checker, SVal location, bool isLoad,
197 const Stmt *S, CheckerContext &C) {
198 ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C);
199 }
200
201public:
202 template <typename CHECKER>
203 static void _register(CHECKER *checker, CheckerManager &mgr) {
204 mgr._registerForLocation(
205 checkfn: CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>));
206 }
207};
208
209class Bind {
210 template <typename CHECKER>
211 static void _checkBind(void *checker, SVal location, SVal val, const Stmt *S,
212 CheckerContext &C) {
213 ((const CHECKER *)checker)->checkBind(location, val, S, C);
214 }
215
216public:
217 template <typename CHECKER>
218 static void _register(CHECKER *checker, CheckerManager &mgr) {
219 mgr._registerForBind(
220 checkfn: CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>));
221 }
222};
223
224class BlockEntrance {
225 template <typename CHECKER>
226 static void _checkBlockEntrance(void *Checker,
227 const clang::BlockEntrance &Entrance,
228 CheckerContext &C) {
229 ((const CHECKER *)Checker)->checkBlockEntrance(Entrance, C);
230 }
231
232public:
233 template <typename CHECKER>
234 static void _register(CHECKER *checker, CheckerManager &mgr) {
235 mgr._registerForBlockEntrance(checkfn: CheckerManager::CheckBlockEntranceFunc(
236 checker, _checkBlockEntrance<CHECKER>));
237 }
238};
239
240class EndAnalysis {
241 template <typename CHECKER>
242 static void _checkEndAnalysis(void *checker, ExplodedGraph &G,
243 BugReporter &BR, ExprEngine &Eng) {
244 ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng);
245 }
246
247public:
248 template <typename CHECKER>
249 static void _register(CHECKER *checker, CheckerManager &mgr) {
250 mgr._registerForEndAnalysis(
251 checkfn: CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>));
252 }
253};
254
255class BeginFunction {
256 template <typename CHECKER>
257 static void _checkBeginFunction(void *checker, CheckerContext &C) {
258 ((const CHECKER *)checker)->checkBeginFunction(C);
259 }
260
261public:
262 template <typename CHECKER>
263 static void _register(CHECKER *checker, CheckerManager &mgr) {
264 mgr._registerForBeginFunction(checkfn: CheckerManager::CheckBeginFunctionFunc(
265 checker, _checkBeginFunction<CHECKER>));
266 }
267};
268
269class EndFunction {
270 template <typename CHECKER>
271 static void _checkEndFunction(void *checker, const ReturnStmt *RS,
272 CheckerContext &C) {
273 ((const CHECKER *)checker)->checkEndFunction(RS, C);
274 }
275
276public:
277 template <typename CHECKER>
278 static void _register(CHECKER *checker, CheckerManager &mgr) {
279 mgr._registerForEndFunction(
280 checkfn: CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>));
281 }
282};
283
284class BranchCondition {
285 template <typename CHECKER>
286 static void _checkBranchCondition(void *checker, const Stmt *Condition,
287 CheckerContext & C) {
288 ((const CHECKER *)checker)->checkBranchCondition(Condition, C);
289 }
290
291public:
292 template <typename CHECKER>
293 static void _register(CHECKER *checker, CheckerManager &mgr) {
294 mgr._registerForBranchCondition(
295 checkfn: CheckerManager::CheckBranchConditionFunc(checker,
296 _checkBranchCondition<CHECKER>));
297 }
298};
299
300class NewAllocator {
301 template <typename CHECKER>
302 static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call,
303 CheckerContext &C) {
304 ((const CHECKER *)checker)->checkNewAllocator(Call, C);
305 }
306
307public:
308 template <typename CHECKER>
309 static void _register(CHECKER *checker, CheckerManager &mgr) {
310 mgr._registerForNewAllocator(
311 checkfn: CheckerManager::CheckNewAllocatorFunc(checker,
312 _checkNewAllocator<CHECKER>));
313 }
314};
315
316class LiveSymbols {
317 template <typename CHECKER>
318 static void _checkLiveSymbols(void *checker, ProgramStateRef state,
319 SymbolReaper &SR) {
320 ((const CHECKER *)checker)->checkLiveSymbols(state, SR);
321 }
322
323public:
324 template <typename CHECKER>
325 static void _register(CHECKER *checker, CheckerManager &mgr) {
326 mgr._registerForLiveSymbols(
327 checkfn: CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>));
328 }
329};
330
331class DeadSymbols {
332 template <typename CHECKER>
333 static void _checkDeadSymbols(void *checker,
334 SymbolReaper &SR, CheckerContext &C) {
335 ((const CHECKER *)checker)->checkDeadSymbols(SR, C);
336 }
337
338public:
339 template <typename CHECKER>
340 static void _register(CHECKER *checker, CheckerManager &mgr) {
341 mgr._registerForDeadSymbols(
342 checkfn: CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>));
343 }
344};
345
346class RegionChanges {
347 template <typename CHECKER>
348 static ProgramStateRef
349 _checkRegionChanges(void *checker,
350 ProgramStateRef state,
351 const InvalidatedSymbols *invalidated,
352 ArrayRef<const MemRegion *> Explicits,
353 ArrayRef<const MemRegion *> Regions,
354 const LocationContext *LCtx,
355 const CallEvent *Call) {
356 return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated,
357 Explicits, Regions,
358 LCtx, Call);
359 }
360
361public:
362 template <typename CHECKER>
363 static void _register(CHECKER *checker, CheckerManager &mgr) {
364 mgr._registerForRegionChanges(
365 checkfn: CheckerManager::CheckRegionChangesFunc(checker,
366 _checkRegionChanges<CHECKER>));
367 }
368};
369
370class PointerEscape {
371 template <typename CHECKER>
372 static ProgramStateRef
373 _checkPointerEscape(void *Checker,
374 ProgramStateRef State,
375 const InvalidatedSymbols &Escaped,
376 const CallEvent *Call,
377 PointerEscapeKind Kind,
378 RegionAndSymbolInvalidationTraits *ETraits) {
379
380 if (!ETraits)
381 return ((const CHECKER *)Checker)->checkPointerEscape(State,
382 Escaped,
383 Call,
384 Kind);
385
386 InvalidatedSymbols RegularEscape;
387 for (SymbolRef Sym : Escaped)
388 if (!ETraits->hasTrait(
389 Sym, IK: RegionAndSymbolInvalidationTraits::TK_PreserveContents) &&
390 !ETraits->hasTrait(
391 Sym, IK: RegionAndSymbolInvalidationTraits::TK_SuppressEscape))
392 RegularEscape.insert(V: Sym);
393
394 if (RegularEscape.empty())
395 return State;
396
397 return ((const CHECKER *)Checker)->checkPointerEscape(State,
398 RegularEscape,
399 Call,
400 Kind);
401 }
402
403public:
404 template <typename CHECKER>
405 static void _register(CHECKER *checker, CheckerManager &mgr) {
406 mgr._registerForPointerEscape(
407 checkfn: CheckerManager::CheckPointerEscapeFunc(checker,
408 _checkPointerEscape<CHECKER>));
409 }
410};
411
412class ConstPointerEscape {
413 template <typename CHECKER>
414 static ProgramStateRef
415 _checkConstPointerEscape(void *Checker,
416 ProgramStateRef State,
417 const InvalidatedSymbols &Escaped,
418 const CallEvent *Call,
419 PointerEscapeKind Kind,
420 RegionAndSymbolInvalidationTraits *ETraits) {
421
422 if (!ETraits)
423 return State;
424
425 InvalidatedSymbols ConstEscape;
426 for (SymbolRef Sym : Escaped) {
427 if (ETraits->hasTrait(
428 Sym, IK: RegionAndSymbolInvalidationTraits::TK_PreserveContents) &&
429 !ETraits->hasTrait(
430 Sym, IK: RegionAndSymbolInvalidationTraits::TK_SuppressEscape))
431 ConstEscape.insert(V: Sym);
432 }
433
434 if (ConstEscape.empty())
435 return State;
436
437 return ((const CHECKER *)Checker)->checkConstPointerEscape(State,
438 ConstEscape,
439 Call,
440 Kind);
441 }
442
443public:
444 template <typename CHECKER>
445 static void _register(CHECKER *checker, CheckerManager &mgr) {
446 mgr._registerForPointerEscape(
447 checkfn: CheckerManager::CheckPointerEscapeFunc(checker,
448 _checkConstPointerEscape<CHECKER>));
449 }
450};
451
452
453template <typename EVENT>
454class Event {
455 template <typename CHECKER>
456 static void _checkEvent(void *checker, const void *event) {
457 ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event);
458 }
459public:
460 template <typename CHECKER>
461 static void _register(CHECKER *checker, CheckerManager &mgr) {
462 mgr._registerListenerForEvent<EVENT>(
463 CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>));
464 }
465};
466
467} // end check namespace
468
469namespace eval {
470
471class Assume {
472 template <typename CHECKER>
473 static ProgramStateRef _evalAssume(void *checker, ProgramStateRef state,
474 SVal cond, bool assumption) {
475 return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
476 }
477
478public:
479 template <typename CHECKER>
480 static void _register(CHECKER *checker, CheckerManager &mgr) {
481 mgr._registerForEvalAssume(
482 checkfn: CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>));
483 }
484};
485
486class Call {
487 template <typename CHECKER>
488 static bool _evalCall(void *checker, const CallEvent &Call,
489 CheckerContext &C) {
490 return ((const CHECKER *)checker)->evalCall(Call, C);
491 }
492
493public:
494 template <typename CHECKER>
495 static void _register(CHECKER *checker, CheckerManager &mgr) {
496 mgr._registerForEvalCall(
497 checkfn: CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>));
498 }
499};
500
501} // end eval namespace
502
503/// A `CheckerFrontend` instance is what the user recognizes as "one checker":
504/// it has a public canonical name (injected from the `CheckerManager`), can be
505/// enabled or disabled, can have associated checker options and can be printed
506/// as the "source" of bug reports.
507/// The singleton instance of a simple `Checker<...>` is-a `CheckerFrontend`
508/// (for historical reasons, to preserve old straightforward code), while the
509/// singleton instance of a `CheckerFamily<...>` class owns multiple
510/// `CheckerFrontend` instances as data members.
511/// Modeling checkers that are hidden from the user but can be enabled or
512/// disabled separately (as dependencies of other checkers) are also considered
513/// to be `CheckerFrontend`s.
514class CheckerFrontend {
515 /// The `Name` is nullopt if and only if the checker is disabled.
516 std::optional<CheckerNameRef> Name;
517
518public:
519 void enable(CheckerManager &Mgr) {
520 assert(!Name && "Checker part registered twice!");
521 Name = Mgr.getCurrentCheckerName();
522 }
523 bool isEnabled() const { return Name.has_value(); }
524 CheckerNameRef getName() const { return *Name; }
525};
526
527/// `CheckerBackend` is an abstract base class that serves as the common
528/// ancestor of all the `Checker<...>` and `CheckerFamily<...>` classes which
529/// can create `ExplodedNode`s (by acting as a `ProgramPointTag`) and can be
530/// registered to handle various checker callbacks. (Moreover the debug
531/// callback `printState` is also introduced here.)
532class CheckerBackend : public ProgramPointTag {
533public:
534 /// Debug state dump callback, see CheckerManager::runCheckersForPrintState.
535 /// Default implementation does nothing.
536 virtual void printState(raw_ostream &Out, ProgramStateRef State,
537 const char *NL, const char *Sep) const;
538};
539
540/// The non-templated common ancestor of all the simple `Checker<...>` classes.
541class CheckerBase : public CheckerFrontend, public CheckerBackend {
542public:
543 /// Attached to nodes created by this checker class when the ExplodedGraph is
544 /// dumped for debugging.
545 StringRef getDebugTag() const override;
546};
547
548/// Simple checker classes that implement one frontend (i.e. checker name)
549/// should derive from this template and specify all the implemented callbacks
550/// (i.e. classes like `check::PreStmt` or `eval::Call`) as template arguments
551/// of `Checker`.
552template <typename... CHECKs>
553class Checker : public CheckerBase, public CHECKs... {
554public:
555 using BlockEntrance = clang::BlockEntrance;
556
557 template <typename CHECKER>
558 static void _register(CHECKER *Chk, CheckerManager &Mgr) {
559 (CHECKs::_register(Chk, Mgr), ...);
560 }
561};
562
563/// Checker families (where a single backend class implements multiple related
564/// frontends) should derive from this template and specify all the implemented
565/// callbacks (i.e. classes like `check::PreStmt` or `eval::Call`) as template
566/// arguments of `FamilyChecker.`
567///
568/// NOTE: Classes deriving from `CheckerFamily` must implement the pure virtual
569/// method `StringRef getDebugTag()` which is inherited from `ProgramPointTag`
570/// and should return the name of the class as a string.
571///
572/// Obviously, this boilerplate is not a good thing, but unfortunately there is
573/// no portable way to stringify the name of a type (e.g. class), so any
574/// portable implementation of `getDebugTag` would need to take the name of
575/// the class from *somewhere* where it's present as a string -- and then
576/// directly placing it in a method override is much simpler than loading it
577/// from `Checkers.td`.
578///
579/// Note that the existing `CLASS` field in `Checkers.td` is not suitable for
580/// our goals, because instead of storing the same class name for each
581/// frontend, in fact each frontendchecker needs to have its own unique value
582/// there (to ensure that the names of the register methods are all unique).
583template <typename... CHECKs>
584class CheckerFamily : public CheckerBackend, public CHECKs... {
585public:
586 using BlockEntrance = clang::BlockEntrance;
587
588 template <typename CHECKER>
589 static void _register(CHECKER *Chk, CheckerManager &Mgr) {
590 (CHECKs::_register(Chk, Mgr), ...);
591 }
592};
593
594template <typename EVENT>
595class EventDispatcher {
596 CheckerManager *Mgr = nullptr;
597public:
598 EventDispatcher() = default;
599
600 template <typename CHECKER>
601 static void _register(CHECKER *checker, CheckerManager &mgr) {
602 mgr._registerDispatcherForEvent<EVENT>();
603 static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr;
604 }
605
606 void dispatchEvent(const EVENT &event) const {
607 Mgr->_dispatchEvent(event);
608 }
609};
610
611/// We dereferenced a location that may be null.
612struct ImplicitNullDerefEvent {
613 SVal Location;
614 bool IsLoad;
615 ExplodedNode *SinkNode;
616 BugReporter *BR;
617 // When true, the dereference is in the source code directly. When false, the
618 // dereference might happen later (for example pointer passed to a parameter
619 // that is marked with nonnull attribute.)
620 bool IsDirectDereference;
621
622 static int Tag;
623};
624
625} // end ento namespace
626
627} // end clang namespace
628
629#endif
630

source code of clang/include/clang/StaticAnalyzer/Core/Checker.h