1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
17 | #include "clang/AST/ExprCXX.h" |
18 | #include "clang/Analysis/CFGStmtMap.h" |
19 | #include "clang/StaticAnalyzer/Core/Checker.h" |
20 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
21 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
22 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
23 | |
24 | using namespace clang; |
25 | using namespace ento; |
26 | |
27 | namespace { |
28 | |
29 | class AnalysisOrderChecker |
30 | : public Checker<check::PreStmt<CastExpr>, |
31 | check::PostStmt<CastExpr>, |
32 | check::PreStmt<ArraySubscriptExpr>, |
33 | check::PostStmt<ArraySubscriptExpr>, |
34 | check::PreStmt<CXXNewExpr>, |
35 | check::PostStmt<CXXNewExpr>, |
36 | check::PreStmt<OffsetOfExpr>, |
37 | check::PostStmt<OffsetOfExpr>, |
38 | check::PreCall, |
39 | check::PostCall, |
40 | check::EndFunction, |
41 | check::NewAllocator, |
42 | check::Bind, |
43 | check::RegionChanges, |
44 | check::LiveSymbols> { |
45 | |
46 | bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const { |
47 | return Opts.getCheckerBooleanOption(this, "*", false) || |
48 | Opts.getCheckerBooleanOption(this, CallbackName, false); |
49 | } |
50 | |
51 | bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const { |
52 | AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions(); |
53 | return isCallbackEnabled(Opts, CallbackName); |
54 | } |
55 | |
56 | bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const { |
57 | AnalyzerOptions &Opts = State->getStateManager().getOwningEngine() |
58 | .getAnalysisManager().getAnalyzerOptions(); |
59 | return isCallbackEnabled(Opts, CallbackName); |
60 | } |
61 | |
62 | public: |
63 | void checkPreStmt(const CastExpr *CE, CheckerContext &C) const { |
64 | if (isCallbackEnabled(C, "PreStmtCastExpr")) |
65 | llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName() |
66 | << ")\n"; |
67 | } |
68 | |
69 | void checkPostStmt(const CastExpr *CE, CheckerContext &C) const { |
70 | if (isCallbackEnabled(C, "PostStmtCastExpr")) |
71 | llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName() |
72 | << ")\n"; |
73 | } |
74 | |
75 | void checkPreStmt(const ArraySubscriptExpr *SubExpr, |
76 | CheckerContext &C) const { |
77 | if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr")) |
78 | llvm::errs() << "PreStmt<ArraySubscriptExpr>\n"; |
79 | } |
80 | |
81 | void checkPostStmt(const ArraySubscriptExpr *SubExpr, |
82 | CheckerContext &C) const { |
83 | if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr")) |
84 | llvm::errs() << "PostStmt<ArraySubscriptExpr>\n"; |
85 | } |
86 | |
87 | void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const { |
88 | if (isCallbackEnabled(C, "PreStmtCXXNewExpr")) |
89 | llvm::errs() << "PreStmt<CXXNewExpr>\n"; |
90 | } |
91 | |
92 | void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const { |
93 | if (isCallbackEnabled(C, "PostStmtCXXNewExpr")) |
94 | llvm::errs() << "PostStmt<CXXNewExpr>\n"; |
95 | } |
96 | |
97 | void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { |
98 | if (isCallbackEnabled(C, "PreStmtOffsetOfExpr")) |
99 | llvm::errs() << "PreStmt<OffsetOfExpr>\n"; |
100 | } |
101 | |
102 | void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { |
103 | if (isCallbackEnabled(C, "PostStmtOffsetOfExpr")) |
104 | llvm::errs() << "PostStmt<OffsetOfExpr>\n"; |
105 | } |
106 | |
107 | void checkPreCall(const CallEvent &Call, CheckerContext &C) const { |
108 | if (isCallbackEnabled(C, "PreCall")) { |
109 | llvm::errs() << "PreCall"; |
110 | if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) |
111 | llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; |
112 | llvm::errs() << '\n'; |
113 | } |
114 | } |
115 | |
116 | void checkPostCall(const CallEvent &Call, CheckerContext &C) const { |
117 | if (isCallbackEnabled(C, "PostCall")) { |
118 | llvm::errs() << "PostCall"; |
119 | if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) |
120 | llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; |
121 | llvm::errs() << '\n'; |
122 | } |
123 | } |
124 | |
125 | void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const { |
126 | if (isCallbackEnabled(C, "EndFunction")) { |
127 | llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n"; |
128 | if (!S) |
129 | return; |
130 | |
131 | llvm::errs() << "CFGElement: "; |
132 | CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap(); |
133 | CFGElement LastElement = Map->getBlock(S)->back(); |
134 | |
135 | if (LastElement.getAs<CFGStmt>()) |
136 | llvm::errs() << "CFGStmt\n"; |
137 | else if (LastElement.getAs<CFGAutomaticObjDtor>()) |
138 | llvm::errs() << "CFGAutomaticObjDtor\n"; |
139 | } |
140 | } |
141 | |
142 | void checkNewAllocator(const CXXNewExpr *CNE, SVal Target, |
143 | CheckerContext &C) const { |
144 | if (isCallbackEnabled(C, "NewAllocator")) |
145 | llvm::errs() << "NewAllocator\n"; |
146 | } |
147 | |
148 | void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const { |
149 | if (isCallbackEnabled(C, "Bind")) |
150 | llvm::errs() << "Bind\n"; |
151 | } |
152 | |
153 | void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const { |
154 | if (isCallbackEnabled(State, "LiveSymbols")) |
155 | llvm::errs() << "LiveSymbols\n"; |
156 | } |
157 | |
158 | ProgramStateRef |
159 | checkRegionChanges(ProgramStateRef State, |
160 | const InvalidatedSymbols *Invalidated, |
161 | ArrayRef<const MemRegion *> ExplicitRegions, |
162 | ArrayRef<const MemRegion *> Regions, |
163 | const LocationContext *LCtx, const CallEvent *Call) const { |
164 | if (isCallbackEnabled(State, "RegionChanges")) |
165 | llvm::errs() << "RegionChanges\n"; |
166 | return State; |
167 | } |
168 | }; |
169 | } |
170 | |
171 | |
172 | |
173 | |
174 | |
175 | void ento::registerAnalysisOrderChecker(CheckerManager &mgr) { |
176 | mgr.registerChecker<AnalysisOrderChecker>(); |
177 | } |
178 | |
179 | bool ento::shouldRegisterAnalysisOrderChecker(const LangOptions &LO) { |
180 | return true; |
181 | } |
182 | |