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 | |
22 | namespace clang { |
23 | namespace ento { |
24 | class BugReporter; |
25 | |
26 | namespace check { |
27 | |
28 | template <typename DECL> |
29 | class 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 | } |
39 | public: |
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 | |
48 | class 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 | |
55 | public: |
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 | |
63 | class 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 | |
72 | public: |
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 | |
81 | template <typename STMT> |
82 | class 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 | } |
91 | public: |
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 | |
100 | template <typename STMT> |
101 | class 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 | } |
110 | public: |
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 | |
119 | class 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 | |
126 | public: |
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 | |
134 | class 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 | |
141 | public: |
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 | |
149 | class 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 | |
156 | public: |
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 | |
164 | class 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 | |
171 | public: |
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 | |
179 | class 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 | |
186 | public: |
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 | |
194 | class 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 | |
201 | public: |
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 | |
209 | class 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 | |
216 | public: |
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 | |
224 | class EndAnalysis { |
225 | template <typename CHECKER> |
226 | static void _checkEndAnalysis(void *checker, ExplodedGraph &G, |
227 | BugReporter &BR, ExprEngine &Eng) { |
228 | ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng); |
229 | } |
230 | |
231 | public: |
232 | template <typename CHECKER> |
233 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
234 | mgr._registerForEndAnalysis( |
235 | checkfn: CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>)); |
236 | } |
237 | }; |
238 | |
239 | class BeginFunction { |
240 | template <typename CHECKER> |
241 | static void _checkBeginFunction(void *checker, CheckerContext &C) { |
242 | ((const CHECKER *)checker)->checkBeginFunction(C); |
243 | } |
244 | |
245 | public: |
246 | template <typename CHECKER> |
247 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
248 | mgr._registerForBeginFunction(checkfn: CheckerManager::CheckBeginFunctionFunc( |
249 | checker, _checkBeginFunction<CHECKER>)); |
250 | } |
251 | }; |
252 | |
253 | class EndFunction { |
254 | template <typename CHECKER> |
255 | static void _checkEndFunction(void *checker, const ReturnStmt *RS, |
256 | CheckerContext &C) { |
257 | ((const CHECKER *)checker)->checkEndFunction(RS, C); |
258 | } |
259 | |
260 | public: |
261 | template <typename CHECKER> |
262 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
263 | mgr._registerForEndFunction( |
264 | checkfn: CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>)); |
265 | } |
266 | }; |
267 | |
268 | class BranchCondition { |
269 | template <typename CHECKER> |
270 | static void _checkBranchCondition(void *checker, const Stmt *Condition, |
271 | CheckerContext & C) { |
272 | ((const CHECKER *)checker)->checkBranchCondition(Condition, C); |
273 | } |
274 | |
275 | public: |
276 | template <typename CHECKER> |
277 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
278 | mgr._registerForBranchCondition( |
279 | checkfn: CheckerManager::CheckBranchConditionFunc(checker, |
280 | _checkBranchCondition<CHECKER>)); |
281 | } |
282 | }; |
283 | |
284 | class NewAllocator { |
285 | template <typename CHECKER> |
286 | static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call, |
287 | CheckerContext &C) { |
288 | ((const CHECKER *)checker)->checkNewAllocator(Call, C); |
289 | } |
290 | |
291 | public: |
292 | template <typename CHECKER> |
293 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
294 | mgr._registerForNewAllocator( |
295 | checkfn: CheckerManager::CheckNewAllocatorFunc(checker, |
296 | _checkNewAllocator<CHECKER>)); |
297 | } |
298 | }; |
299 | |
300 | class LiveSymbols { |
301 | template <typename CHECKER> |
302 | static void _checkLiveSymbols(void *checker, ProgramStateRef state, |
303 | SymbolReaper &SR) { |
304 | ((const CHECKER *)checker)->checkLiveSymbols(state, SR); |
305 | } |
306 | |
307 | public: |
308 | template <typename CHECKER> |
309 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
310 | mgr._registerForLiveSymbols( |
311 | checkfn: CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>)); |
312 | } |
313 | }; |
314 | |
315 | class DeadSymbols { |
316 | template <typename CHECKER> |
317 | static void _checkDeadSymbols(void *checker, |
318 | SymbolReaper &SR, CheckerContext &C) { |
319 | ((const CHECKER *)checker)->checkDeadSymbols(SR, C); |
320 | } |
321 | |
322 | public: |
323 | template <typename CHECKER> |
324 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
325 | mgr._registerForDeadSymbols( |
326 | checkfn: CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>)); |
327 | } |
328 | }; |
329 | |
330 | class RegionChanges { |
331 | template <typename CHECKER> |
332 | static ProgramStateRef |
333 | _checkRegionChanges(void *checker, |
334 | ProgramStateRef state, |
335 | const InvalidatedSymbols *invalidated, |
336 | ArrayRef<const MemRegion *> Explicits, |
337 | ArrayRef<const MemRegion *> Regions, |
338 | const LocationContext *LCtx, |
339 | const CallEvent *Call) { |
340 | return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated, |
341 | Explicits, Regions, |
342 | LCtx, Call); |
343 | } |
344 | |
345 | public: |
346 | template <typename CHECKER> |
347 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
348 | mgr._registerForRegionChanges( |
349 | checkfn: CheckerManager::CheckRegionChangesFunc(checker, |
350 | _checkRegionChanges<CHECKER>)); |
351 | } |
352 | }; |
353 | |
354 | class PointerEscape { |
355 | template <typename CHECKER> |
356 | static ProgramStateRef |
357 | _checkPointerEscape(void *Checker, |
358 | ProgramStateRef State, |
359 | const InvalidatedSymbols &Escaped, |
360 | const CallEvent *Call, |
361 | PointerEscapeKind Kind, |
362 | RegionAndSymbolInvalidationTraits *ETraits) { |
363 | |
364 | if (!ETraits) |
365 | return ((const CHECKER *)Checker)->checkPointerEscape(State, |
366 | Escaped, |
367 | Call, |
368 | Kind); |
369 | |
370 | InvalidatedSymbols RegularEscape; |
371 | for (SymbolRef Sym : Escaped) |
372 | if (!ETraits->hasTrait( |
373 | Sym, IK: RegionAndSymbolInvalidationTraits::TK_PreserveContents) && |
374 | !ETraits->hasTrait( |
375 | Sym, IK: RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) |
376 | RegularEscape.insert(V: Sym); |
377 | |
378 | if (RegularEscape.empty()) |
379 | return State; |
380 | |
381 | return ((const CHECKER *)Checker)->checkPointerEscape(State, |
382 | RegularEscape, |
383 | Call, |
384 | Kind); |
385 | } |
386 | |
387 | public: |
388 | template <typename CHECKER> |
389 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
390 | mgr._registerForPointerEscape( |
391 | checkfn: CheckerManager::CheckPointerEscapeFunc(checker, |
392 | _checkPointerEscape<CHECKER>)); |
393 | } |
394 | }; |
395 | |
396 | class ConstPointerEscape { |
397 | template <typename CHECKER> |
398 | static ProgramStateRef |
399 | _checkConstPointerEscape(void *Checker, |
400 | ProgramStateRef State, |
401 | const InvalidatedSymbols &Escaped, |
402 | const CallEvent *Call, |
403 | PointerEscapeKind Kind, |
404 | RegionAndSymbolInvalidationTraits *ETraits) { |
405 | |
406 | if (!ETraits) |
407 | return State; |
408 | |
409 | InvalidatedSymbols ConstEscape; |
410 | for (SymbolRef Sym : Escaped) { |
411 | if (ETraits->hasTrait( |
412 | Sym, IK: RegionAndSymbolInvalidationTraits::TK_PreserveContents) && |
413 | !ETraits->hasTrait( |
414 | Sym, IK: RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) |
415 | ConstEscape.insert(V: Sym); |
416 | } |
417 | |
418 | if (ConstEscape.empty()) |
419 | return State; |
420 | |
421 | return ((const CHECKER *)Checker)->checkConstPointerEscape(State, |
422 | ConstEscape, |
423 | Call, |
424 | Kind); |
425 | } |
426 | |
427 | public: |
428 | template <typename CHECKER> |
429 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
430 | mgr._registerForPointerEscape( |
431 | checkfn: CheckerManager::CheckPointerEscapeFunc(checker, |
432 | _checkConstPointerEscape<CHECKER>)); |
433 | } |
434 | }; |
435 | |
436 | |
437 | template <typename EVENT> |
438 | class Event { |
439 | template <typename CHECKER> |
440 | static void _checkEvent(void *checker, const void *event) { |
441 | ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); |
442 | } |
443 | public: |
444 | template <typename CHECKER> |
445 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
446 | mgr._registerListenerForEvent<EVENT>( |
447 | CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>)); |
448 | } |
449 | }; |
450 | |
451 | } // end check namespace |
452 | |
453 | namespace eval { |
454 | |
455 | class Assume { |
456 | template <typename CHECKER> |
457 | static ProgramStateRef _evalAssume(void *checker, ProgramStateRef state, |
458 | SVal cond, bool assumption) { |
459 | return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); |
460 | } |
461 | |
462 | public: |
463 | template <typename CHECKER> |
464 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
465 | mgr._registerForEvalAssume( |
466 | checkfn: CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>)); |
467 | } |
468 | }; |
469 | |
470 | class Call { |
471 | template <typename CHECKER> |
472 | static bool _evalCall(void *checker, const CallEvent &Call, |
473 | CheckerContext &C) { |
474 | return ((const CHECKER *)checker)->evalCall(Call, C); |
475 | } |
476 | |
477 | public: |
478 | template <typename CHECKER> |
479 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
480 | mgr._registerForEvalCall( |
481 | checkfn: CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>)); |
482 | } |
483 | }; |
484 | |
485 | } // end eval namespace |
486 | |
487 | class CheckerBase : public ProgramPointTag { |
488 | CheckerNameRef Name; |
489 | friend class ::clang::ento::CheckerManager; |
490 | |
491 | public: |
492 | StringRef getTagDescription() const override; |
493 | CheckerNameRef getCheckerName() const; |
494 | |
495 | /// See CheckerManager::runCheckersForPrintState. |
496 | virtual void printState(raw_ostream &Out, ProgramStateRef State, |
497 | const char *NL, const char *Sep) const { } |
498 | }; |
499 | |
500 | /// Dump checker name to stream. |
501 | raw_ostream& operator<<(raw_ostream &Out, const CheckerBase &Checker); |
502 | |
503 | /// Tag that can use a checker name as a message provider |
504 | /// (see SimpleProgramPointTag). |
505 | class CheckerProgramPointTag : public SimpleProgramPointTag { |
506 | public: |
507 | CheckerProgramPointTag(StringRef CheckerName, StringRef Msg); |
508 | CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg); |
509 | }; |
510 | |
511 | template <typename CHECK1, typename... CHECKs> |
512 | class Checker : public CHECK1, public CHECKs..., public CheckerBase { |
513 | public: |
514 | template <typename CHECKER> |
515 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
516 | CHECK1::_register(checker, mgr); |
517 | Checker<CHECKs...>::_register(checker, mgr); |
518 | } |
519 | }; |
520 | |
521 | template <typename CHECK1> |
522 | class Checker<CHECK1> : public CHECK1, public CheckerBase { |
523 | public: |
524 | template <typename CHECKER> |
525 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
526 | CHECK1::_register(checker, mgr); |
527 | } |
528 | }; |
529 | |
530 | template <typename EVENT> |
531 | class EventDispatcher { |
532 | CheckerManager *Mgr = nullptr; |
533 | public: |
534 | EventDispatcher() = default; |
535 | |
536 | template <typename CHECKER> |
537 | static void _register(CHECKER *checker, CheckerManager &mgr) { |
538 | mgr._registerDispatcherForEvent<EVENT>(); |
539 | static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr; |
540 | } |
541 | |
542 | void dispatchEvent(const EVENT &event) const { |
543 | Mgr->_dispatchEvent(event); |
544 | } |
545 | }; |
546 | |
547 | /// We dereferenced a location that may be null. |
548 | struct ImplicitNullDerefEvent { |
549 | SVal Location; |
550 | bool IsLoad; |
551 | ExplodedNode *SinkNode; |
552 | BugReporter *BR; |
553 | // When true, the dereference is in the source code directly. When false, the |
554 | // dereference might happen later (for example pointer passed to a parameter |
555 | // that is marked with nonnull attribute.) |
556 | bool IsDirectDereference; |
557 | |
558 | static int Tag; |
559 | }; |
560 | |
561 | } // end ento namespace |
562 | |
563 | } // end clang namespace |
564 | |
565 | #endif |
566 | |