blob: 5f068dc9f04b69e0fca86dafb7e477e179871522 [file] [log] [blame]
Ted Kremenek53500662009-07-22 17:55:28 +00001// BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- C++ -*--//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines a set of BugReporter "visitors" which can be used to
11// enhance the diagnostics reported for a bug.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/Expr.h"
16#include "clang/AST/ExprObjC.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000017#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
Ted Kremenek53500662009-07-22 17:55:28 +000021
22using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000023using namespace ento;
Ted Kremenek53500662009-07-22 17:55:28 +000024
25//===----------------------------------------------------------------------===//
26// Utility functions.
27//===----------------------------------------------------------------------===//
28
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000029const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
Ted Kremenek53500662009-07-22 17:55:28 +000030 // Pattern match for a few useful cases (do something smarter later):
31 // a[0], p->f, *p
32 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
Mike Stump1eb44332009-09-09 15:08:12 +000033
Ted Kremenek53500662009-07-22 17:55:28 +000034 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
John McCall2de56d12010-08-25 11:45:40 +000035 if (U->getOpcode() == UO_Deref)
Ted Kremenek53500662009-07-22 17:55:28 +000036 return U->getSubExpr()->IgnoreParenCasts();
37 }
38 else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
39 return ME->getBase()->IgnoreParenCasts();
40 }
41 else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
Ted Kremenek53500662009-07-22 17:55:28 +000042 return AE->getBase();
43 }
Mike Stump1eb44332009-09-09 15:08:12 +000044
45 return NULL;
Ted Kremenek53500662009-07-22 17:55:28 +000046}
47
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000048const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) {
Zhongxing Xu6403b572009-09-02 13:26:26 +000049 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
Ted Kremenek53500662009-07-22 17:55:28 +000050 if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
51 return BE->getRHS();
52 return NULL;
53}
54
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000055const Stmt *bugreporter::GetCalleeExpr(const ExplodedNode *N) {
Zhongxing Xud99f3612009-09-02 08:10:35 +000056 // Callee is checked as a PreVisit to the CallExpr.
57 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
Ted Kremenek53500662009-07-22 17:55:28 +000058 if (const CallExpr *CE = dyn_cast<CallExpr>(S))
59 return CE->getCallee();
60 return NULL;
61}
62
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000063const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
Ted Kremenek53500662009-07-22 17:55:28 +000064 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
65 if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
66 return RS->getRetValue();
67 return NULL;
68}
69
70//===----------------------------------------------------------------------===//
71// Definitions for bug reporter visitors.
72//===----------------------------------------------------------------------===//
73
74namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000075class FindLastStoreBRVisitor : public BugReporterVisitor {
Ted Kremenek53500662009-07-22 17:55:28 +000076 const MemRegion *R;
77 SVal V;
78 bool satisfied;
Zhongxing Xuc5619d92009-08-06 01:32:16 +000079 const ExplodedNode *StoreSite;
Ted Kremenek53500662009-07-22 17:55:28 +000080public:
81 FindLastStoreBRVisitor(SVal v, const MemRegion *r)
82 : R(r), V(v), satisfied(false), StoreSite(0) {}
Mike Stump1eb44332009-09-09 15:08:12 +000083
Ted Kremenek1b431022010-03-20 18:01:57 +000084 virtual void Profile(llvm::FoldingSetNodeID &ID) const {
85 static int tag = 0;
86 ID.AddPointer(&tag);
87 ID.AddPointer(R);
88 ID.Add(V);
89 }
90
Zhongxing Xuc5619d92009-08-06 01:32:16 +000091 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
92 const ExplodedNode *PrevN,
Ted Kremenek53500662009-07-22 17:55:28 +000093 BugReporterContext& BRC) {
Mike Stump1eb44332009-09-09 15:08:12 +000094
Ted Kremenek53500662009-07-22 17:55:28 +000095 if (satisfied)
96 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +000097
98 if (!StoreSite) {
Zhongxing Xuc5619d92009-08-06 01:32:16 +000099 const ExplodedNode *Node = N, *Last = NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000100
Ted Kremenek53500662009-07-22 17:55:28 +0000101 for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000102
Ted Kremenek53500662009-07-22 17:55:28 +0000103 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
104 if (const PostStmt *P = Node->getLocationAs<PostStmt>())
105 if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
106 if (DS->getSingleDecl() == VR->getDecl()) {
107 Last = Node;
108 break;
109 }
110 }
Mike Stump1eb44332009-09-09 15:08:12 +0000111
Ted Kremenek13976632010-02-08 16:18:51 +0000112 if (Node->getState()->getSVal(R) != V)
Ted Kremenek53500662009-07-22 17:55:28 +0000113 break;
114 }
Mike Stump1eb44332009-09-09 15:08:12 +0000115
Ted Kremenek53500662009-07-22 17:55:28 +0000116 if (!Node || !Last) {
117 satisfied = true;
118 return NULL;
119 }
Mike Stump1eb44332009-09-09 15:08:12 +0000120
Ted Kremenek53500662009-07-22 17:55:28 +0000121 StoreSite = Last;
122 }
Mike Stump1eb44332009-09-09 15:08:12 +0000123
Ted Kremenek53500662009-07-22 17:55:28 +0000124 if (StoreSite != N)
125 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000126
Ted Kremenek53500662009-07-22 17:55:28 +0000127 satisfied = true;
Ted Kremenek1b431022010-03-20 18:01:57 +0000128 llvm::SmallString<256> sbuf;
129 llvm::raw_svector_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000130
Ted Kremenek53500662009-07-22 17:55:28 +0000131 if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
132 if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
Mike Stump1eb44332009-09-09 15:08:12 +0000133
Ted Kremenek53500662009-07-22 17:55:28 +0000134 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
Benjamin Kramer900fc632010-04-17 09:33:03 +0000135 os << "Variable '" << VR->getDecl() << "' ";
Ted Kremenek53500662009-07-22 17:55:28 +0000136 }
137 else
138 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000139
Ted Kremenek53500662009-07-22 17:55:28 +0000140 if (isa<loc::ConcreteInt>(V)) {
141 bool b = false;
Ted Kremenek53500662009-07-22 17:55:28 +0000142 if (R->isBoundable()) {
143 if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
Zhongxing Xu018220c2010-08-11 06:10:55 +0000144 if (TR->getValueType()->isObjCObjectPointerType()) {
Ted Kremenek53500662009-07-22 17:55:28 +0000145 os << "initialized to nil";
146 b = true;
147 }
148 }
149 }
Mike Stump1eb44332009-09-09 15:08:12 +0000150
Ted Kremenek53500662009-07-22 17:55:28 +0000151 if (!b)
152 os << "initialized to a null pointer value";
153 }
154 else if (isa<nonloc::ConcreteInt>(V)) {
155 os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
156 }
157 else if (V.isUndef()) {
158 if (isa<VarRegion>(R)) {
159 const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
160 if (VD->getInit())
161 os << "initialized to a garbage value";
162 else
Mike Stump1eb44332009-09-09 15:08:12 +0000163 os << "declared without an initial value";
164 }
Ted Kremenek53500662009-07-22 17:55:28 +0000165 }
166 }
167 }
Mike Stump1eb44332009-09-09 15:08:12 +0000168
169 if (os.str().empty()) {
Ted Kremenek53500662009-07-22 17:55:28 +0000170 if (isa<loc::ConcreteInt>(V)) {
171 bool b = false;
Ted Kremenek53500662009-07-22 17:55:28 +0000172 if (R->isBoundable()) {
173 if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
Zhongxing Xu018220c2010-08-11 06:10:55 +0000174 if (TR->getValueType()->isObjCObjectPointerType()) {
Ted Kremenek53500662009-07-22 17:55:28 +0000175 os << "nil object reference stored to ";
176 b = true;
177 }
178 }
179 }
Mike Stump1eb44332009-09-09 15:08:12 +0000180
Ted Kremenek53500662009-07-22 17:55:28 +0000181 if (!b)
182 os << "Null pointer value stored to ";
183 }
184 else if (V.isUndef()) {
185 os << "Uninitialized value stored to ";
186 }
Ted Kremenek592362b2009-08-18 01:05:30 +0000187 else if (isa<nonloc::ConcreteInt>(V)) {
188 os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
189 << " is assigned to ";
190 }
Ted Kremenek53500662009-07-22 17:55:28 +0000191 else
192 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000193
Ted Kremenek53500662009-07-22 17:55:28 +0000194 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
Benjamin Kramer900fc632010-04-17 09:33:03 +0000195 os << '\'' << VR->getDecl() << '\'';
Ted Kremenek53500662009-07-22 17:55:28 +0000196 }
197 else
198 return NULL;
199 }
Mike Stump1eb44332009-09-09 15:08:12 +0000200
Ted Kremenek53500662009-07-22 17:55:28 +0000201 // FIXME: Refactor this into BugReporterContext.
Mike Stump1eb44332009-09-09 15:08:12 +0000202 const Stmt *S = 0;
Ted Kremenek53500662009-07-22 17:55:28 +0000203 ProgramPoint P = N->getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000204
Ted Kremenek53500662009-07-22 17:55:28 +0000205 if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
Zhongxing Xu03509ae2010-07-20 06:22:24 +0000206 const CFGBlock *BSrc = BE->getSrc();
Ted Kremenek53500662009-07-22 17:55:28 +0000207 S = BSrc->getTerminatorCondition();
208 }
209 else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
210 S = PS->getStmt();
211 }
Mike Stump1eb44332009-09-09 15:08:12 +0000212
Ted Kremenek53500662009-07-22 17:55:28 +0000213 if (!S)
214 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000215
Ted Kremenek53500662009-07-22 17:55:28 +0000216 // Construct a new PathDiagnosticPiece.
217 PathDiagnosticLocation L(S, BRC.getSourceManager());
218 return new PathDiagnosticEventPiece(L, os.str());
219 }
220};
221
222
223static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
224 SVal V) {
225 BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
226}
227
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +0000228class TrackConstraintBRVisitor : public BugReporterVisitor {
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000229 DefinedSVal Constraint;
Ted Kremenek53500662009-07-22 17:55:28 +0000230 const bool Assumption;
231 bool isSatisfied;
232public:
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000233 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
Ted Kremenek53500662009-07-22 17:55:28 +0000234 : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000235
Ted Kremenek1b431022010-03-20 18:01:57 +0000236 void Profile(llvm::FoldingSetNodeID &ID) const {
237 static int tag = 0;
238 ID.AddPointer(&tag);
239 ID.AddBoolean(Assumption);
240 ID.Add(Constraint);
241 }
242
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000243 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
244 const ExplodedNode *PrevN,
Ted Kremenek53500662009-07-22 17:55:28 +0000245 BugReporterContext& BRC) {
246 if (isSatisfied)
247 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000248
Ted Kremenek53500662009-07-22 17:55:28 +0000249 // Check if in the previous state it was feasible for this constraint
250 // to *not* be true.
Ted Kremenek28f47b92010-12-01 22:16:56 +0000251 if (PrevN->getState()->assume(Constraint, !Assumption)) {
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000252
Ted Kremenek53500662009-07-22 17:55:28 +0000253 isSatisfied = true;
Mike Stump1eb44332009-09-09 15:08:12 +0000254
Ted Kremenek53500662009-07-22 17:55:28 +0000255 // As a sanity check, make sure that the negation of the constraint
256 // was infeasible in the current state. If it is feasible, we somehow
257 // missed the transition point.
Ted Kremenek28f47b92010-12-01 22:16:56 +0000258 if (N->getState()->assume(Constraint, !Assumption))
Ted Kremenek53500662009-07-22 17:55:28 +0000259 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000260
Ted Kremenek53500662009-07-22 17:55:28 +0000261 // We found the transition point for the constraint. We now need to
Mike Stump1eb44332009-09-09 15:08:12 +0000262 // pretty-print the constraint. (work-in-progress)
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000263 std::string sbuf;
264 llvm::raw_string_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000265
Ted Kremenek53500662009-07-22 17:55:28 +0000266 if (isa<Loc>(Constraint)) {
267 os << "Assuming pointer value is ";
268 os << (Assumption ? "non-null" : "null");
269 }
Mike Stump1eb44332009-09-09 15:08:12 +0000270
Ted Kremenek53500662009-07-22 17:55:28 +0000271 if (os.str().empty())
272 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000273
Ted Kremenek53500662009-07-22 17:55:28 +0000274 // FIXME: Refactor this into BugReporterContext.
Mike Stump1eb44332009-09-09 15:08:12 +0000275 const Stmt *S = 0;
Ted Kremenek53500662009-07-22 17:55:28 +0000276 ProgramPoint P = N->getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000277
Ted Kremenek53500662009-07-22 17:55:28 +0000278 if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
Zhongxing Xu03509ae2010-07-20 06:22:24 +0000279 const CFGBlock *BSrc = BE->getSrc();
Ted Kremenek53500662009-07-22 17:55:28 +0000280 S = BSrc->getTerminatorCondition();
281 }
282 else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
283 S = PS->getStmt();
284 }
Mike Stump1eb44332009-09-09 15:08:12 +0000285
Ted Kremenek53500662009-07-22 17:55:28 +0000286 if (!S)
287 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000288
Ted Kremenek53500662009-07-22 17:55:28 +0000289 // Construct a new PathDiagnosticPiece.
290 PathDiagnosticLocation L(S, BRC.getSourceManager());
291 return new PathDiagnosticEventPiece(L, os.str());
292 }
Mike Stump1eb44332009-09-09 15:08:12 +0000293
Ted Kremenek53500662009-07-22 17:55:28 +0000294 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000295 }
Ted Kremenek53500662009-07-22 17:55:28 +0000296};
297} // end anonymous namespace
298
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000299static void registerTrackConstraint(BugReporterContext& BRC,
300 DefinedSVal Constraint,
Ted Kremenek53500662009-07-22 17:55:28 +0000301 bool Assumption) {
Mike Stump1eb44332009-09-09 15:08:12 +0000302 BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
Ted Kremenek53500662009-07-22 17:55:28 +0000303}
304
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +0000305void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
306 const void *data,
307 const ExplodedNode* N) {
Mike Stump1eb44332009-09-09 15:08:12 +0000308
Ted Kremenek592362b2009-08-18 01:05:30 +0000309 const Stmt *S = static_cast<const Stmt*>(data);
Mike Stump1eb44332009-09-09 15:08:12 +0000310
Ted Kremenek53500662009-07-22 17:55:28 +0000311 if (!S)
312 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000313
Ted Kremenek53500662009-07-22 17:55:28 +0000314 GRStateManager &StateMgr = BRC.getStateManager();
Ted Kremenek88299892011-07-28 23:07:59 +0000315
316 // Walk through nodes until we get one that matches the statement
317 // exactly.
318 while (N) {
319 const ProgramPoint &pp = N->getLocation();
320 if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
321 if (ps->getStmt() == S)
322 break;
323 }
324 N = *N->pred_begin();
325 }
326
327 if (!N)
328 return;
329
Mike Stump1eb44332009-09-09 15:08:12 +0000330 const GRState *state = N->getState();
331
Ted Kremenek892697d2010-12-16 07:46:53 +0000332 // Walk through lvalue-to-rvalue conversions.
Mike Stump1eb44332009-09-09 15:08:12 +0000333 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
334 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
Ted Kremenek53500662009-07-22 17:55:28 +0000335 const VarRegion *R =
Ted Kremenek892697d2010-12-16 07:46:53 +0000336 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
Mike Stump1eb44332009-09-09 15:08:12 +0000337
Ted Kremenek53500662009-07-22 17:55:28 +0000338 // What did we load?
Ted Kremenek892697d2010-12-16 07:46:53 +0000339 SVal V = state->getSVal(loc::MemRegionVal(R));
Mike Stump1eb44332009-09-09 15:08:12 +0000340
341 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
Ted Kremenek53500662009-07-22 17:55:28 +0000342 || V.isUndef()) {
Ted Kremenek94fd0b82010-02-16 08:33:59 +0000343 ::registerFindLastStore(BRC, R, V);
Ted Kremenek53500662009-07-22 17:55:28 +0000344 }
345 }
346 }
Mike Stump1eb44332009-09-09 15:08:12 +0000347
Ted Kremenek13976632010-02-08 16:18:51 +0000348 SVal V = state->getSValAsScalarOrLoc(S);
Mike Stump1eb44332009-09-09 15:08:12 +0000349
Ted Kremenek53500662009-07-22 17:55:28 +0000350 // Uncomment this to find cases where we aren't properly getting the
351 // base value that was dereferenced.
352 // assert(!V.isUnknownOrUndef());
Mike Stump1eb44332009-09-09 15:08:12 +0000353
Ted Kremenek53500662009-07-22 17:55:28 +0000354 // Is it a symbolic value?
355 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
356 const SubRegion *R = cast<SubRegion>(L->getRegion());
357 while (R && !isa<SymbolicRegion>(R)) {
358 R = dyn_cast<SubRegion>(R->getSuperRegion());
359 }
Mike Stump1eb44332009-09-09 15:08:12 +0000360
Ted Kremenek53500662009-07-22 17:55:28 +0000361 if (R) {
362 assert(isa<SymbolicRegion>(R));
363 registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
364 }
365 }
366}
Ted Kremenek94fd0b82010-02-16 08:33:59 +0000367
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +0000368void bugreporter::registerFindLastStore(BugReporterContext& BRC,
369 const void *data,
370 const ExplodedNode* N) {
Ted Kremenek94fd0b82010-02-16 08:33:59 +0000371
372 const MemRegion *R = static_cast<const MemRegion*>(data);
373
374 if (!R)
375 return;
376
377 const GRState *state = N->getState();
378 SVal V = state->getSVal(R);
379
380 if (V.isUnknown())
381 return;
382
383 BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
384}
Ted Kremenekff7f7362010-03-20 18:02:01 +0000385
386
387namespace {
388class NilReceiverVisitor : public BugReporterVisitor {
389public:
390 NilReceiverVisitor() {}
391
392 void Profile(llvm::FoldingSetNodeID &ID) const {
393 static int x = 0;
394 ID.AddPointer(&x);
395 }
396
397 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
398 const ExplodedNode *PrevN,
399 BugReporterContext& BRC) {
400
401 const PostStmt *P = N->getLocationAs<PostStmt>();
402 if (!P)
403 return 0;
404 const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
405 if (!ME)
406 return 0;
Douglas Gregor04badcf2010-04-21 00:45:42 +0000407 const Expr *Receiver = ME->getInstanceReceiver();
Ted Kremenekff7f7362010-03-20 18:02:01 +0000408 if (!Receiver)
409 return 0;
410 const GRState *state = N->getState();
411 const SVal &V = state->getSVal(Receiver);
412 const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
413 if (!DV)
414 return 0;
Ted Kremenek28f47b92010-12-01 22:16:56 +0000415 state = state->assume(*DV, true);
Ted Kremenekff7f7362010-03-20 18:02:01 +0000416 if (state)
417 return 0;
418
419 // The receiver was nil, and hence the method was skipped.
420 // Register a BugReporterVisitor to issue a message telling us how
421 // the receiver was null.
422 bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N);
423 // Issue a message saying that the method was skipped.
424 PathDiagnosticLocation L(Receiver, BRC.getSourceManager());
425 return new PathDiagnosticEventPiece(L, "No method actually called "
426 "because the receiver is nil");
427 }
428};
429} // end anonymous namespace
430
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +0000431void bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) {
Ted Kremenekff7f7362010-03-20 18:02:01 +0000432 BRC.addVisitor(new NilReceiverVisitor());
433}
Tom Care2bbbe502010-09-02 23:30:22 +0000434
435// Registers every VarDecl inside a Stmt with a last store vistor.
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +0000436void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC,
Tom Care2bbbe502010-09-02 23:30:22 +0000437 const void *stmt,
438 const ExplodedNode *N) {
439 const Stmt *S = static_cast<const Stmt *>(stmt);
440
441 std::deque<const Stmt *> WorkList;
442
443 WorkList.push_back(S);
444
445 while (!WorkList.empty()) {
446 const Stmt *Head = WorkList.front();
447 WorkList.pop_front();
448
449 GRStateManager &StateMgr = BRC.getStateManager();
450 const GRState *state = N->getState();
451
452 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) {
453 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
454 const VarRegion *R =
455 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
456
457 // What did we load?
458 SVal V = state->getSVal(S);
459
460 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
461 ::registerFindLastStore(BRC, R, V);
462 }
463 }
464 }
465
466 for (Stmt::const_child_iterator I = Head->child_begin();
467 I != Head->child_end(); ++I)
468 WorkList.push_back(*I);
469 }
470}
Ted Kremenek993124e2011-08-06 06:54:45 +0000471
472//===----------------------------------------------------------------------===//
473// Visitor that tries to report interesting diagnostics from conditions.
474//===----------------------------------------------------------------------===//
475
476namespace {
477class ConditionVisitor : public BugReporterVisitor {
478public:
479 void Profile(llvm::FoldingSetNodeID &ID) const {
480 static int x = 0;
481 ID.AddPointer(&x);
482 }
483
484 virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
485 const ExplodedNode *Prev,
486 BugReporterContext &BRC);
487
488 PathDiagnosticPiece *VisitTerminator(const Stmt *Term,
489 const GRState *CurrentState,
490 const GRState *PrevState,
491 const CFGBlock *srcBlk,
492 const CFGBlock *dstBlk,
493 BugReporterContext &BRC);
494
495 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
496 bool tookTrue,
497 BugReporterContext &BRC);
498
499 PathDiagnosticPiece *VisitTrueTest(const Expr *Cond,
500 const DeclRefExpr *DR,
501 const bool tookTrue,
502 BugReporterContext &BRC);
503
504};
505}
506
507PathDiagnosticPiece *ConditionVisitor::VisitNode(const ExplodedNode *N,
508 const ExplodedNode *Prev,
509 BugReporterContext &BRC) {
510
511 const ProgramPoint &progPoint = N->getLocation();
512
513 // If an assumption was made on a branch, it should be caught
514 // here by looking at the state transition.
515 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) {
516 const CFGBlock *srcBlk = BE->getSrc();
517
518 if (const Stmt *term = srcBlk->getTerminator()) {
519 const GRState *CurrentState = N->getState();
520 const GRState *PrevState = Prev->getState();
521 if (CurrentState != PrevState)
522 return VisitTerminator(term, CurrentState, PrevState,
523 srcBlk, BE->getDst(),
524 BRC);
525 }
526
527 return 0;
528 }
529
530 return 0;
531}
532
533PathDiagnosticPiece *
534ConditionVisitor::VisitTerminator(const Stmt *Term,
535 const GRState *CurrentState,
536 const GRState *PrevState,
537 const CFGBlock *srcBlk,
538 const CFGBlock *dstBlk,
539 BugReporterContext &BRC) {
540
541 assert(CurrentState != PrevState);
542 const Expr *Cond = 0;
543
544 switch (Term->getStmtClass()) {
545 default:
546 return 0;
547 case Stmt::IfStmtClass:
548 Cond = cast<IfStmt>(Term)->getCond();
549 break;
550 case Stmt::ConditionalOperatorClass:
551 Cond = cast<ConditionalOperator>(Term)->getCond();
552 break;
553 }
554
555 assert(Cond);
556 assert(srcBlk->succ_size() == 2);
557 const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk;
558 return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()),
559 tookTrue, BRC);
560}
561
562PathDiagnosticPiece *
563ConditionVisitor::VisitTrueTest(const Expr *Cond,
564 bool tookTrue,
565 BugReporterContext &BRC) {
566
567 const Expr *Ex = Cond;
568
569 while (true)
570 switch (Ex->getStmtClass()) {
571 default:
572 return 0;
573 case Stmt::DeclRefExprClass:
574 return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC);
575 case Stmt::UnaryOperatorClass: {
576 const UnaryOperator *UO = cast<UnaryOperator>(Ex);
577 if (UO->getOpcode() == UO_LNot) {
578 tookTrue = !tookTrue;
579 Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext());
580 continue;
581 }
582 return 0;
583 }
584 }
585}
586
587PathDiagnosticPiece *
588ConditionVisitor::VisitTrueTest(const Expr *Cond,
589 const DeclRefExpr *DR,
590 const bool tookTrue,
591 BugReporterContext &BRC) {
592
593 const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
594 if (!VD)
595 return 0;
596
597 llvm::SmallString<256> Buf;
598 llvm::raw_svector_ostream Out(Buf);
599
600 Out << "Assuming '";
601 VD->getDeclName().printName(Out);
602 Out << "' is ";
603
604 QualType VDTy = VD->getType();
605
606 if (VDTy->isPointerType())
607 Out << (tookTrue ? "non-null" : "null");
608 else if (VDTy->isObjCObjectPointerType())
609 Out << (tookTrue ? "non-nil" : "nil");
610 else if (VDTy->isScalarType())
611 Out << (tookTrue ? "not equal to 0" : "0");
612 else
613 return 0;
614
615 PathDiagnosticLocation Loc(Cond, BRC.getSourceManager());
616 return new PathDiagnosticEventPiece(Loc, Out.str());
617}
618
619void bugreporter::registerConditionVisitor(BugReporterContext &BRC) {
620 BRC.addVisitor(new ConditionVisitor());
621}
622