blob: 06cee5bcd1bc721f9a13ab0de990f1214bc4a688 [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 Kremenek6b676302010-01-25 17:10:22 +000017#include "clang/Checker/BugReporter/BugReporter.h"
18#include "clang/Checker/BugReporter/PathDiagnostic.h"
Benjamin Kramer5e2d2c22010-03-27 21:19:47 +000019#include "clang/Checker/PathSensitive/ExplodedGraph.h"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000020#include "clang/Checker/PathSensitive/GRState.h"
Ted Kremenek53500662009-07-22 17:55:28 +000021
22using namespace clang;
23
24//===----------------------------------------------------------------------===//
25// Utility functions.
26//===----------------------------------------------------------------------===//
27
Zhongxing Xuc5619d92009-08-06 01:32:16 +000028const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
Ted Kremenek53500662009-07-22 17:55:28 +000029 // Pattern match for a few useful cases (do something smarter later):
30 // a[0], p->f, *p
31 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
Mike Stump1eb44332009-09-09 15:08:12 +000032
Ted Kremenek53500662009-07-22 17:55:28 +000033 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
34 if (U->getOpcode() == UnaryOperator::Deref)
35 return U->getSubExpr()->IgnoreParenCasts();
36 }
37 else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
38 return ME->getBase()->IgnoreParenCasts();
39 }
40 else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
41 // Retrieve the base for arrays since BasicStoreManager doesn't know how
42 // to reason about them.
43 return AE->getBase();
44 }
Mike Stump1eb44332009-09-09 15:08:12 +000045
46 return NULL;
Ted Kremenek53500662009-07-22 17:55:28 +000047}
48
49const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000050clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
Ted Kremenek53500662009-07-22 17:55:28 +000051 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
52 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
53 return ME->getReceiver();
54 return NULL;
55}
56
57const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000058clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
Zhongxing Xu6403b572009-09-02 13:26:26 +000059 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
Ted Kremenek53500662009-07-22 17:55:28 +000060 if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
61 return BE->getRHS();
62 return NULL;
63}
64
65const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000066clang::bugreporter::GetCalleeExpr(const ExplodedNode *N) {
Zhongxing Xud99f3612009-09-02 08:10:35 +000067 // Callee is checked as a PreVisit to the CallExpr.
68 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
Ted Kremenek53500662009-07-22 17:55:28 +000069 if (const CallExpr *CE = dyn_cast<CallExpr>(S))
70 return CE->getCallee();
71 return NULL;
72}
73
74const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000075clang::bugreporter::GetRetValExpr(const ExplodedNode *N) {
Ted Kremenek53500662009-07-22 17:55:28 +000076 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
77 if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
78 return RS->getRetValue();
79 return NULL;
80}
81
82//===----------------------------------------------------------------------===//
83// Definitions for bug reporter visitors.
84//===----------------------------------------------------------------------===//
85
86namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000087class FindLastStoreBRVisitor : public BugReporterVisitor {
Ted Kremenek53500662009-07-22 17:55:28 +000088 const MemRegion *R;
89 SVal V;
90 bool satisfied;
Zhongxing Xuc5619d92009-08-06 01:32:16 +000091 const ExplodedNode *StoreSite;
Ted Kremenek53500662009-07-22 17:55:28 +000092public:
93 FindLastStoreBRVisitor(SVal v, const MemRegion *r)
94 : R(r), V(v), satisfied(false), StoreSite(0) {}
Mike Stump1eb44332009-09-09 15:08:12 +000095
Ted Kremenek1b431022010-03-20 18:01:57 +000096 virtual void Profile(llvm::FoldingSetNodeID &ID) const {
97 static int tag = 0;
98 ID.AddPointer(&tag);
99 ID.AddPointer(R);
100 ID.Add(V);
101 }
102
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000103 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
104 const ExplodedNode *PrevN,
Ted Kremenek53500662009-07-22 17:55:28 +0000105 BugReporterContext& BRC) {
Mike Stump1eb44332009-09-09 15:08:12 +0000106
Ted Kremenek53500662009-07-22 17:55:28 +0000107 if (satisfied)
108 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000109
110 if (!StoreSite) {
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000111 const ExplodedNode *Node = N, *Last = NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000112
Ted Kremenek53500662009-07-22 17:55:28 +0000113 for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000114
Ted Kremenek53500662009-07-22 17:55:28 +0000115 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
116 if (const PostStmt *P = Node->getLocationAs<PostStmt>())
117 if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
118 if (DS->getSingleDecl() == VR->getDecl()) {
119 Last = Node;
120 break;
121 }
122 }
Mike Stump1eb44332009-09-09 15:08:12 +0000123
Ted Kremenek13976632010-02-08 16:18:51 +0000124 if (Node->getState()->getSVal(R) != V)
Ted Kremenek53500662009-07-22 17:55:28 +0000125 break;
126 }
Mike Stump1eb44332009-09-09 15:08:12 +0000127
Ted Kremenek53500662009-07-22 17:55:28 +0000128 if (!Node || !Last) {
129 satisfied = true;
130 return NULL;
131 }
Mike Stump1eb44332009-09-09 15:08:12 +0000132
Ted Kremenek53500662009-07-22 17:55:28 +0000133 StoreSite = Last;
134 }
Mike Stump1eb44332009-09-09 15:08:12 +0000135
Ted Kremenek53500662009-07-22 17:55:28 +0000136 if (StoreSite != N)
137 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000138
Ted Kremenek53500662009-07-22 17:55:28 +0000139 satisfied = true;
Ted Kremenek1b431022010-03-20 18:01:57 +0000140 llvm::SmallString<256> sbuf;
141 llvm::raw_svector_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000142
Ted Kremenek53500662009-07-22 17:55:28 +0000143 if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
144 if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
Mike Stump1eb44332009-09-09 15:08:12 +0000145
Ted Kremenek53500662009-07-22 17:55:28 +0000146 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
147 os << "Variable '" << VR->getDecl()->getNameAsString() << "' ";
148 }
149 else
150 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000151
Ted Kremenek53500662009-07-22 17:55:28 +0000152 if (isa<loc::ConcreteInt>(V)) {
153 bool b = false;
154 ASTContext &C = BRC.getASTContext();
155 if (R->isBoundable()) {
156 if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
157 if (TR->getValueType(C)->isObjCObjectPointerType()) {
158 os << "initialized to nil";
159 b = true;
160 }
161 }
162 }
Mike Stump1eb44332009-09-09 15:08:12 +0000163
Ted Kremenek53500662009-07-22 17:55:28 +0000164 if (!b)
165 os << "initialized to a null pointer value";
166 }
167 else if (isa<nonloc::ConcreteInt>(V)) {
168 os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
169 }
170 else if (V.isUndef()) {
171 if (isa<VarRegion>(R)) {
172 const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
173 if (VD->getInit())
174 os << "initialized to a garbage value";
175 else
Mike Stump1eb44332009-09-09 15:08:12 +0000176 os << "declared without an initial value";
177 }
Ted Kremenek53500662009-07-22 17:55:28 +0000178 }
179 }
180 }
Mike Stump1eb44332009-09-09 15:08:12 +0000181
182 if (os.str().empty()) {
Ted Kremenek53500662009-07-22 17:55:28 +0000183 if (isa<loc::ConcreteInt>(V)) {
184 bool b = false;
185 ASTContext &C = BRC.getASTContext();
186 if (R->isBoundable()) {
187 if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
188 if (TR->getValueType(C)->isObjCObjectPointerType()) {
189 os << "nil object reference stored to ";
190 b = true;
191 }
192 }
193 }
Mike Stump1eb44332009-09-09 15:08:12 +0000194
Ted Kremenek53500662009-07-22 17:55:28 +0000195 if (!b)
196 os << "Null pointer value stored to ";
197 }
198 else if (V.isUndef()) {
199 os << "Uninitialized value stored to ";
200 }
Ted Kremenek592362b2009-08-18 01:05:30 +0000201 else if (isa<nonloc::ConcreteInt>(V)) {
202 os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
203 << " is assigned to ";
204 }
Ted Kremenek53500662009-07-22 17:55:28 +0000205 else
206 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000207
Ted Kremenek53500662009-07-22 17:55:28 +0000208 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
209 os << '\'' << VR->getDecl()->getNameAsString() << '\'';
210 }
211 else
212 return NULL;
213 }
Mike Stump1eb44332009-09-09 15:08:12 +0000214
Ted Kremenek53500662009-07-22 17:55:28 +0000215 // FIXME: Refactor this into BugReporterContext.
Mike Stump1eb44332009-09-09 15:08:12 +0000216 const Stmt *S = 0;
Ted Kremenek53500662009-07-22 17:55:28 +0000217 ProgramPoint P = N->getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000218
Ted Kremenek53500662009-07-22 17:55:28 +0000219 if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
220 CFGBlock *BSrc = BE->getSrc();
221 S = BSrc->getTerminatorCondition();
222 }
223 else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
224 S = PS->getStmt();
225 }
Mike Stump1eb44332009-09-09 15:08:12 +0000226
Ted Kremenek53500662009-07-22 17:55:28 +0000227 if (!S)
228 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000229
Ted Kremenek53500662009-07-22 17:55:28 +0000230 // Construct a new PathDiagnosticPiece.
231 PathDiagnosticLocation L(S, BRC.getSourceManager());
232 return new PathDiagnosticEventPiece(L, os.str());
233 }
234};
235
236
237static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
238 SVal V) {
239 BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
240}
241
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +0000242class TrackConstraintBRVisitor : public BugReporterVisitor {
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000243 DefinedSVal Constraint;
Ted Kremenek53500662009-07-22 17:55:28 +0000244 const bool Assumption;
245 bool isSatisfied;
246public:
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000247 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
Ted Kremenek53500662009-07-22 17:55:28 +0000248 : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000249
Ted Kremenek1b431022010-03-20 18:01:57 +0000250 void Profile(llvm::FoldingSetNodeID &ID) const {
251 static int tag = 0;
252 ID.AddPointer(&tag);
253 ID.AddBoolean(Assumption);
254 ID.Add(Constraint);
255 }
256
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000257 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
258 const ExplodedNode *PrevN,
Ted Kremenek53500662009-07-22 17:55:28 +0000259 BugReporterContext& BRC) {
260 if (isSatisfied)
261 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000262
Ted Kremenek53500662009-07-22 17:55:28 +0000263 // Check if in the previous state it was feasible for this constraint
264 // to *not* be true.
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000265 if (PrevN->getState()->Assume(Constraint, !Assumption)) {
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000266
Ted Kremenek53500662009-07-22 17:55:28 +0000267 isSatisfied = true;
Mike Stump1eb44332009-09-09 15:08:12 +0000268
Ted Kremenek53500662009-07-22 17:55:28 +0000269 // As a sanity check, make sure that the negation of the constraint
270 // was infeasible in the current state. If it is feasible, we somehow
271 // missed the transition point.
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000272 if (N->getState()->Assume(Constraint, !Assumption))
Ted Kremenek53500662009-07-22 17:55:28 +0000273 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000274
Ted Kremenek53500662009-07-22 17:55:28 +0000275 // We found the transition point for the constraint. We now need to
Mike Stump1eb44332009-09-09 15:08:12 +0000276 // pretty-print the constraint. (work-in-progress)
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000277 std::string sbuf;
278 llvm::raw_string_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000279
Ted Kremenek53500662009-07-22 17:55:28 +0000280 if (isa<Loc>(Constraint)) {
281 os << "Assuming pointer value is ";
282 os << (Assumption ? "non-null" : "null");
283 }
Mike Stump1eb44332009-09-09 15:08:12 +0000284
Ted Kremenek53500662009-07-22 17:55:28 +0000285 if (os.str().empty())
286 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000287
Ted Kremenek53500662009-07-22 17:55:28 +0000288 // FIXME: Refactor this into BugReporterContext.
Mike Stump1eb44332009-09-09 15:08:12 +0000289 const Stmt *S = 0;
Ted Kremenek53500662009-07-22 17:55:28 +0000290 ProgramPoint P = N->getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000291
Ted Kremenek53500662009-07-22 17:55:28 +0000292 if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
293 CFGBlock *BSrc = BE->getSrc();
294 S = BSrc->getTerminatorCondition();
295 }
296 else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
297 S = PS->getStmt();
298 }
Mike Stump1eb44332009-09-09 15:08:12 +0000299
Ted Kremenek53500662009-07-22 17:55:28 +0000300 if (!S)
301 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000302
Ted Kremenek53500662009-07-22 17:55:28 +0000303 // Construct a new PathDiagnosticPiece.
304 PathDiagnosticLocation L(S, BRC.getSourceManager());
305 return new PathDiagnosticEventPiece(L, os.str());
306 }
Mike Stump1eb44332009-09-09 15:08:12 +0000307
Ted Kremenek53500662009-07-22 17:55:28 +0000308 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000309 }
Ted Kremenek53500662009-07-22 17:55:28 +0000310};
311} // end anonymous namespace
312
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000313static void registerTrackConstraint(BugReporterContext& BRC,
314 DefinedSVal Constraint,
Ted Kremenek53500662009-07-22 17:55:28 +0000315 bool Assumption) {
Mike Stump1eb44332009-09-09 15:08:12 +0000316 BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
Ted Kremenek53500662009-07-22 17:55:28 +0000317}
318
319void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
Ted Kremenek592362b2009-08-18 01:05:30 +0000320 const void *data,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000321 const ExplodedNode* N) {
Mike Stump1eb44332009-09-09 15:08:12 +0000322
Ted Kremenek592362b2009-08-18 01:05:30 +0000323 const Stmt *S = static_cast<const Stmt*>(data);
Mike Stump1eb44332009-09-09 15:08:12 +0000324
Ted Kremenek53500662009-07-22 17:55:28 +0000325 if (!S)
326 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000327
Ted Kremenek53500662009-07-22 17:55:28 +0000328 GRStateManager &StateMgr = BRC.getStateManager();
Mike Stump1eb44332009-09-09 15:08:12 +0000329 const GRState *state = N->getState();
330
331 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
332 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
Ted Kremenek53500662009-07-22 17:55:28 +0000333 const VarRegion *R =
Ted Kremenekd17da2b2009-08-21 22:28:32 +0000334 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
Mike Stump1eb44332009-09-09 15:08:12 +0000335
Ted Kremenek53500662009-07-22 17:55:28 +0000336 // What did we load?
Ted Kremenek13976632010-02-08 16:18:51 +0000337 SVal V = state->getSVal(S);
Mike Stump1eb44332009-09-09 15:08:12 +0000338
339 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
Ted Kremenek53500662009-07-22 17:55:28 +0000340 || V.isUndef()) {
Ted Kremenek94fd0b82010-02-16 08:33:59 +0000341 ::registerFindLastStore(BRC, R, V);
Ted Kremenek53500662009-07-22 17:55:28 +0000342 }
343 }
344 }
Mike Stump1eb44332009-09-09 15:08:12 +0000345
Ted Kremenek13976632010-02-08 16:18:51 +0000346 SVal V = state->getSValAsScalarOrLoc(S);
Mike Stump1eb44332009-09-09 15:08:12 +0000347
Ted Kremenek53500662009-07-22 17:55:28 +0000348 // Uncomment this to find cases where we aren't properly getting the
349 // base value that was dereferenced.
350 // assert(!V.isUnknownOrUndef());
Mike Stump1eb44332009-09-09 15:08:12 +0000351
Ted Kremenek53500662009-07-22 17:55:28 +0000352 // Is it a symbolic value?
353 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
354 const SubRegion *R = cast<SubRegion>(L->getRegion());
355 while (R && !isa<SymbolicRegion>(R)) {
356 R = dyn_cast<SubRegion>(R->getSuperRegion());
357 }
Mike Stump1eb44332009-09-09 15:08:12 +0000358
Ted Kremenek53500662009-07-22 17:55:28 +0000359 if (R) {
360 assert(isa<SymbolicRegion>(R));
361 registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
362 }
363 }
364}
Ted Kremenek94fd0b82010-02-16 08:33:59 +0000365
366void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC,
367 const void *data,
368 const ExplodedNode* N) {
369
370 const MemRegion *R = static_cast<const MemRegion*>(data);
371
372 if (!R)
373 return;
374
375 const GRState *state = N->getState();
376 SVal V = state->getSVal(R);
377
378 if (V.isUnknown())
379 return;
380
381 BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
382}
Ted Kremenekff7f7362010-03-20 18:02:01 +0000383
384
385namespace {
386class NilReceiverVisitor : public BugReporterVisitor {
387public:
388 NilReceiverVisitor() {}
389
390 void Profile(llvm::FoldingSetNodeID &ID) const {
391 static int x = 0;
392 ID.AddPointer(&x);
393 }
394
395 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
396 const ExplodedNode *PrevN,
397 BugReporterContext& BRC) {
398
399 const PostStmt *P = N->getLocationAs<PostStmt>();
400 if (!P)
401 return 0;
402 const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
403 if (!ME)
404 return 0;
405 const Expr *Receiver = ME->getReceiver();
406 if (!Receiver)
407 return 0;
408 const GRState *state = N->getState();
409 const SVal &V = state->getSVal(Receiver);
410 const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
411 if (!DV)
412 return 0;
413 state = state->Assume(*DV, true);
414 if (state)
415 return 0;
416
417 // The receiver was nil, and hence the method was skipped.
418 // Register a BugReporterVisitor to issue a message telling us how
419 // the receiver was null.
420 bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N);
421 // Issue a message saying that the method was skipped.
422 PathDiagnosticLocation L(Receiver, BRC.getSourceManager());
423 return new PathDiagnosticEventPiece(L, "No method actually called "
424 "because the receiver is nil");
425 }
426};
427} // end anonymous namespace
428
429void clang::bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) {
430 BRC.addVisitor(new NilReceiverVisitor());
431}