17
17
#include " clang/AST/DeclCXX.h"
18
18
#include " clang/AST/ExprCXX.h"
19
19
#include " clang/AST/Type.h"
20
+ #include " clang/Basic/LLVM.h"
20
21
#include " clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
21
22
#include " clang/StaticAnalyzer/Core/BugReporter/BugType.h"
22
23
#include " clang/StaticAnalyzer/Core/Checker.h"
23
24
#include " clang/StaticAnalyzer/Core/CheckerManager.h"
24
25
#include " clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
25
26
#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
27
+ #include " clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
26
28
#include " clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
27
29
#include " clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
30
+ #include " clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
31
+ #include < string>
28
32
29
33
using namespace clang ;
30
34
using namespace ento ;
@@ -49,8 +53,6 @@ class SmartPtrModeling
49
53
const LocationContext *LCtx, const CallEvent *Call) const ;
50
54
51
55
private:
52
- ProgramStateRef updateTrackedRegion (const CallEvent &Call, CheckerContext &C,
53
- const MemRegion *ThisValRegion) const ;
54
56
void handleReset (const CallEvent &Call, CheckerContext &C) const ;
55
57
void handleRelease (const CallEvent &Call, CheckerContext &C) const ;
56
58
void handleSwap (const CallEvent &Call, CheckerContext &C) const ;
@@ -131,11 +133,11 @@ bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
131
133
bool SmartPtrModeling::evalCall (const CallEvent &Call,
132
134
CheckerContext &C) const {
133
135
136
+ ProgramStateRef State = C.getState ();
134
137
if (!smartptr::isStdSmartPtrCall (Call))
135
138
return false ;
136
139
137
140
if (isNullAfterMoveMethod (Call)) {
138
- ProgramStateRef State = C.getState ();
139
141
const MemRegion *ThisR =
140
142
cast<CXXInstanceCall>(&Call)->getCXXThisVal ().getAsRegion ();
141
143
@@ -159,12 +161,46 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
159
161
if (CC->getDecl ()->isCopyOrMoveConstructor ())
160
162
return false ;
161
163
162
- const MemRegion *ThisValRegion = CC->getCXXThisVal ().getAsRegion ();
163
- if (!ThisValRegion )
164
+ const MemRegion *ThisRegion = CC->getCXXThisVal ().getAsRegion ();
165
+ if (!ThisRegion )
164
166
return false ;
165
167
166
- auto State = updateTrackedRegion (Call, C, ThisValRegion);
167
- C.addTransition (State);
168
+ if (Call.getNumArgs () == 0 ) {
169
+ auto NullVal = C.getSValBuilder ().makeNull ();
170
+ State = State->set <TrackedRegionMap>(ThisRegion, NullVal);
171
+
172
+ C.addTransition (
173
+ State, C.getNoteTag ([ThisRegion](PathSensitiveBugReport &BR,
174
+ llvm::raw_ostream &OS) {
175
+ if (&BR.getBugType () != smartptr::getNullDereferenceBugType () ||
176
+ !BR.isInteresting (ThisRegion))
177
+ return ;
178
+ OS << " Default constructed smart pointer " ;
179
+ ThisRegion->printPretty (OS);
180
+ OS << " is null" ;
181
+ }));
182
+ } else {
183
+ const auto *TrackingExpr = Call.getArgExpr (0 );
184
+ assert (TrackingExpr->getType ()->isPointerType () &&
185
+ " Adding a non pointer value to TrackedRegionMap" );
186
+ auto ArgVal = Call.getArgSVal (0 );
187
+ State = State->set <TrackedRegionMap>(ThisRegion, ArgVal);
188
+
189
+ C.addTransition (State, C.getNoteTag ([ThisRegion, TrackingExpr,
190
+ ArgVal](PathSensitiveBugReport &BR,
191
+ llvm::raw_ostream &OS) {
192
+ if (&BR.getBugType () != smartptr::getNullDereferenceBugType () ||
193
+ !BR.isInteresting (ThisRegion))
194
+ return ;
195
+ bugreporter::trackExpressionValue (BR.getErrorNode (), TrackingExpr, BR);
196
+ OS << " Smart pointer " ;
197
+ ThisRegion->printPretty (OS);
198
+ if (ArgVal.isZeroConstant ())
199
+ OS << " is constructed using a null value" ;
200
+ else
201
+ OS << " is constructed" ;
202
+ }));
203
+ }
168
204
return true ;
169
205
}
170
206
@@ -207,37 +243,65 @@ ProgramStateRef SmartPtrModeling::checkRegionChanges(
207
243
208
244
void SmartPtrModeling::handleReset (const CallEvent &Call,
209
245
CheckerContext &C) const {
246
+ ProgramStateRef State = C.getState ();
210
247
const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
211
248
if (!IC)
212
249
return ;
213
250
214
- const MemRegion *ThisValRegion = IC->getCXXThisVal ().getAsRegion ();
215
- if (!ThisValRegion )
251
+ const MemRegion *ThisRegion = IC->getCXXThisVal ().getAsRegion ();
252
+ if (!ThisRegion )
216
253
return ;
217
- auto State = updateTrackedRegion (Call, C, ThisValRegion);
218
- C.addTransition (State);
254
+
255
+ assert (Call.getArgExpr (0 )->getType ()->isPointerType () &&
256
+ " Adding a non pointer value to TrackedRegionMap" );
257
+ State = State->set <TrackedRegionMap>(ThisRegion, Call.getArgSVal (0 ));
258
+ const auto *TrackingExpr = Call.getArgExpr (0 );
259
+ C.addTransition (
260
+ State, C.getNoteTag ([ThisRegion, TrackingExpr](PathSensitiveBugReport &BR,
261
+ llvm::raw_ostream &OS) {
262
+ if (&BR.getBugType () != smartptr::getNullDereferenceBugType () ||
263
+ !BR.isInteresting (ThisRegion))
264
+ return ;
265
+ bugreporter::trackExpressionValue (BR.getErrorNode (), TrackingExpr, BR);
266
+ OS << " Smart pointer " ;
267
+ ThisRegion->printPretty (OS);
268
+ OS << " reset using a null value" ;
269
+ }));
219
270
// TODO: Make sure to ivalidate the region in the Store if we don't have
220
271
// time to model all methods.
221
272
}
222
273
223
274
void SmartPtrModeling::handleRelease (const CallEvent &Call,
224
275
CheckerContext &C) const {
276
+ ProgramStateRef State = C.getState ();
225
277
const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
226
278
if (!IC)
227
279
return ;
228
280
229
- const MemRegion *ThisValRegion = IC->getCXXThisVal ().getAsRegion ();
230
- if (!ThisValRegion )
281
+ const MemRegion *ThisRegion = IC->getCXXThisVal ().getAsRegion ();
282
+ if (!ThisRegion )
231
283
return ;
232
284
233
- auto State = updateTrackedRegion (Call, C, ThisValRegion );
285
+ const auto *InnerPointVal = State-> get <TrackedRegionMap>(ThisRegion );
234
286
235
- const auto *InnerPointVal = State->get <TrackedRegionMap>(ThisValRegion);
236
287
if (InnerPointVal) {
237
288
State = State->BindExpr (Call.getOriginExpr (), C.getLocationContext (),
238
289
*InnerPointVal);
239
290
}
240
- C.addTransition (State);
291
+
292
+ auto ValueToUpdate = C.getSValBuilder ().makeNull ();
293
+ State = State->set <TrackedRegionMap>(ThisRegion, ValueToUpdate);
294
+
295
+ C.addTransition (State, C.getNoteTag ([ThisRegion](PathSensitiveBugReport &BR,
296
+ llvm::raw_ostream &OS) {
297
+ if (&BR.getBugType () != smartptr::getNullDereferenceBugType () ||
298
+ !BR.isInteresting (ThisRegion))
299
+ return ;
300
+
301
+ OS << " Smart pointer " ;
302
+ ThisRegion->printPretty (OS);
303
+ OS << " is released and set to null" ;
304
+ }));
241
305
// TODO: Add support to enable MallocChecker to start tracking the raw
242
306
// pointer.
243
307
}
@@ -267,27 +331,18 @@ void SmartPtrModeling::handleSwap(const CallEvent &Call,
267
331
State = updateSwappedRegion (State, ThisRegion, ArgRegionInnerPointerVal);
268
332
State = updateSwappedRegion (State, ArgRegion, ThisRegionInnerPointerVal);
269
333
270
- C.addTransition (State);
271
- }
272
-
273
- ProgramStateRef
274
- SmartPtrModeling::updateTrackedRegion (const CallEvent &Call, CheckerContext &C,
275
- const MemRegion *ThisValRegion) const {
276
- // TODO: Refactor and clean up handling too many things.
277
- ProgramStateRef State = C.getState ();
278
- auto NumArgs = Call.getNumArgs ();
279
-
280
- if (NumArgs == 0 ) {
281
- auto NullSVal = C.getSValBuilder ().makeNull ();
282
- State = State->set <TrackedRegionMap>(ThisValRegion, NullSVal);
283
- } else if (NumArgs == 1 ) {
284
- auto ArgVal = Call.getArgSVal (0 );
285
- assert (Call.getArgExpr (0 )->getType ()->isPointerType () &&
286
- " Adding a non pointer value to TrackedRegionMap" );
287
- State = State->set <TrackedRegionMap>(ThisValRegion, ArgVal);
288
- }
289
-
290
- return State;
334
+ C.addTransition (
335
+ State, C.getNoteTag ([ThisRegion, ArgRegion](PathSensitiveBugReport &BR,
336
+ llvm::raw_ostream &OS) {
337
+ if (&BR.getBugType () != smartptr::getNullDereferenceBugType () ||
338
+ !BR.isInteresting (ThisRegion))
339
+ return ;
340
+ BR.markInteresting (ArgRegion);
341
+ OS << " Swapped null smart pointer " ;
342
+ ArgRegion->printPretty (OS);
343
+ OS << " with smart pointer " ;
344
+ ThisRegion->printPretty (OS);
345
+ }));
291
346
}
292
347
293
348
void ento::registerSmartPtrModeling (CheckerManager &Mgr) {
0 commit comments