blob: 7104f91d882ff374529c0f466964c6a5baaee6b6 [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"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000019#include "clang/Checker/PathSensitive/GRState.h"
Ted Kremenek53500662009-07-22 17:55:28 +000020
21using namespace clang;
22
23//===----------------------------------------------------------------------===//
24// Utility functions.
25//===----------------------------------------------------------------------===//
26
Zhongxing Xuc5619d92009-08-06 01:32:16 +000027const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
Ted Kremenek53500662009-07-22 17:55:28 +000028 // Pattern match for a few useful cases (do something smarter later):
29 // a[0], p->f, *p
30 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
Mike Stump1eb44332009-09-09 15:08:12 +000031
Ted Kremenek53500662009-07-22 17:55:28 +000032 if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
33 if (U->getOpcode() == UnaryOperator::Deref)
34 return U->getSubExpr()->IgnoreParenCasts();
35 }
36 else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
37 return ME->getBase()->IgnoreParenCasts();
38 }
39 else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
40 // Retrieve the base for arrays since BasicStoreManager doesn't know how
41 // to reason about them.
42 return AE->getBase();
43 }
Mike Stump1eb44332009-09-09 15:08:12 +000044
45 return NULL;
Ted Kremenek53500662009-07-22 17:55:28 +000046}
47
48const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000049clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
Ted Kremenek53500662009-07-22 17:55:28 +000050 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
51 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
52 return ME->getReceiver();
53 return NULL;
54}
55
56const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000057clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
Zhongxing Xu6403b572009-09-02 13:26:26 +000058 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
Ted Kremenek53500662009-07-22 17:55:28 +000059 if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
60 return BE->getRHS();
61 return NULL;
62}
63
64const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000065clang::bugreporter::GetCalleeExpr(const ExplodedNode *N) {
Zhongxing Xud99f3612009-09-02 08:10:35 +000066 // Callee is checked as a PreVisit to the CallExpr.
67 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
Ted Kremenek53500662009-07-22 17:55:28 +000068 if (const CallExpr *CE = dyn_cast<CallExpr>(S))
69 return CE->getCallee();
70 return NULL;
71}
72
73const Stmt*
Zhongxing Xuc5619d92009-08-06 01:32:16 +000074clang::bugreporter::GetRetValExpr(const ExplodedNode *N) {
Ted Kremenek53500662009-07-22 17:55:28 +000075 const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
76 if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
77 return RS->getRetValue();
78 return NULL;
79}
80
81//===----------------------------------------------------------------------===//
82// Definitions for bug reporter visitors.
83//===----------------------------------------------------------------------===//
84
85namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000086class FindLastStoreBRVisitor : public BugReporterVisitor {
Ted Kremenek53500662009-07-22 17:55:28 +000087 const MemRegion *R;
88 SVal V;
89 bool satisfied;
Zhongxing Xuc5619d92009-08-06 01:32:16 +000090 const ExplodedNode *StoreSite;
Ted Kremenek53500662009-07-22 17:55:28 +000091public:
92 FindLastStoreBRVisitor(SVal v, const MemRegion *r)
93 : R(r), V(v), satisfied(false), StoreSite(0) {}
Mike Stump1eb44332009-09-09 15:08:12 +000094
Ted Kremenek1b431022010-03-20 18:01:57 +000095 virtual void Profile(llvm::FoldingSetNodeID &ID) const {
96 static int tag = 0;
97 ID.AddPointer(&tag);
98 ID.AddPointer(R);
99 ID.Add(V);
100 }
101
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000102 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
103 const ExplodedNode *PrevN,
Ted Kremenek53500662009-07-22 17:55:28 +0000104 BugReporterContext& BRC) {
Mike Stump1eb44332009-09-09 15:08:12 +0000105
Ted Kremenek53500662009-07-22 17:55:28 +0000106 if (satisfied)
107 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000108
109 if (!StoreSite) {
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000110 const ExplodedNode *Node = N, *Last = NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000111
Ted Kremenek53500662009-07-22 17:55:28 +0000112 for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000113
Ted Kremenek53500662009-07-22 17:55:28 +0000114 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
115 if (const PostStmt *P = Node->getLocationAs<PostStmt>())
116 if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
117 if (DS->getSingleDecl() == VR->getDecl()) {
118 Last = Node;
119 break;
120 }
121 }
Mike Stump1eb44332009-09-09 15:08:12 +0000122
Ted Kremenek13976632010-02-08 16:18:51 +0000123 if (Node->getState()->getSVal(R) != V)
Ted Kremenek53500662009-07-22 17:55:28 +0000124 break;
125 }
Mike Stump1eb44332009-09-09 15:08:12 +0000126
Ted Kremenek53500662009-07-22 17:55:28 +0000127 if (!Node || !Last) {
128 satisfied = true;
129 return NULL;
130 }
Mike Stump1eb44332009-09-09 15:08:12 +0000131
Ted Kremenek53500662009-07-22 17:55:28 +0000132 StoreSite = Last;
133 }
Mike Stump1eb44332009-09-09 15:08:12 +0000134
Ted Kremenek53500662009-07-22 17:55:28 +0000135 if (StoreSite != N)
136 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000137
Ted Kremenek53500662009-07-22 17:55:28 +0000138 satisfied = true;
Ted Kremenek1b431022010-03-20 18:01:57 +0000139 llvm::SmallString<256> sbuf;
140 llvm::raw_svector_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000141
Ted Kremenek53500662009-07-22 17:55:28 +0000142 if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
143 if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
Mike Stump1eb44332009-09-09 15:08:12 +0000144
Ted Kremenek53500662009-07-22 17:55:28 +0000145 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
146 os << "Variable '" << VR->getDecl()->getNameAsString() << "' ";
147 }
148 else
149 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000150
Ted Kremenek53500662009-07-22 17:55:28 +0000151 if (isa<loc::ConcreteInt>(V)) {
152 bool b = false;
153 ASTContext &C = BRC.getASTContext();
154 if (R->isBoundable()) {
155 if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
156 if (TR->getValueType(C)->isObjCObjectPointerType()) {
157 os << "initialized to nil";
158 b = true;
159 }
160 }
161 }
Mike Stump1eb44332009-09-09 15:08:12 +0000162
Ted Kremenek53500662009-07-22 17:55:28 +0000163 if (!b)
164 os << "initialized to a null pointer value";
165 }
166 else if (isa<nonloc::ConcreteInt>(V)) {
167 os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
168 }
169 else if (V.isUndef()) {
170 if (isa<VarRegion>(R)) {
171 const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
172 if (VD->getInit())
173 os << "initialized to a garbage value";
174 else
Mike Stump1eb44332009-09-09 15:08:12 +0000175 os << "declared without an initial value";
176 }
Ted Kremenek53500662009-07-22 17:55:28 +0000177 }
178 }
179 }
Mike Stump1eb44332009-09-09 15:08:12 +0000180
181 if (os.str().empty()) {
Ted Kremenek53500662009-07-22 17:55:28 +0000182 if (isa<loc::ConcreteInt>(V)) {
183 bool b = false;
184 ASTContext &C = BRC.getASTContext();
185 if (R->isBoundable()) {
186 if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
187 if (TR->getValueType(C)->isObjCObjectPointerType()) {
188 os << "nil object reference stored to ";
189 b = true;
190 }
191 }
192 }
Mike Stump1eb44332009-09-09 15:08:12 +0000193
Ted Kremenek53500662009-07-22 17:55:28 +0000194 if (!b)
195 os << "Null pointer value stored to ";
196 }
197 else if (V.isUndef()) {
198 os << "Uninitialized value stored to ";
199 }
Ted Kremenek592362b2009-08-18 01:05:30 +0000200 else if (isa<nonloc::ConcreteInt>(V)) {
201 os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
202 << " is assigned to ";
203 }
Ted Kremenek53500662009-07-22 17:55:28 +0000204 else
205 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000206
Ted Kremenek53500662009-07-22 17:55:28 +0000207 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
208 os << '\'' << VR->getDecl()->getNameAsString() << '\'';
209 }
210 else
211 return NULL;
212 }
Mike Stump1eb44332009-09-09 15:08:12 +0000213
Ted Kremenek53500662009-07-22 17:55:28 +0000214 // FIXME: Refactor this into BugReporterContext.
Mike Stump1eb44332009-09-09 15:08:12 +0000215 const Stmt *S = 0;
Ted Kremenek53500662009-07-22 17:55:28 +0000216 ProgramPoint P = N->getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000217
Ted Kremenek53500662009-07-22 17:55:28 +0000218 if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
219 CFGBlock *BSrc = BE->getSrc();
220 S = BSrc->getTerminatorCondition();
221 }
222 else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
223 S = PS->getStmt();
224 }
Mike Stump1eb44332009-09-09 15:08:12 +0000225
Ted Kremenek53500662009-07-22 17:55:28 +0000226 if (!S)
227 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000228
Ted Kremenek53500662009-07-22 17:55:28 +0000229 // Construct a new PathDiagnosticPiece.
230 PathDiagnosticLocation L(S, BRC.getSourceManager());
231 return new PathDiagnosticEventPiece(L, os.str());
232 }
233};
234
235
236static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
237 SVal V) {
238 BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
239}
240
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +0000241class TrackConstraintBRVisitor : public BugReporterVisitor {
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000242 DefinedSVal Constraint;
Ted Kremenek53500662009-07-22 17:55:28 +0000243 const bool Assumption;
244 bool isSatisfied;
245public:
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000246 TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
Ted Kremenek53500662009-07-22 17:55:28 +0000247 : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000248
Ted Kremenek1b431022010-03-20 18:01:57 +0000249 void Profile(llvm::FoldingSetNodeID &ID) const {
250 static int tag = 0;
251 ID.AddPointer(&tag);
252 ID.AddBoolean(Assumption);
253 ID.Add(Constraint);
254 }
255
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000256 PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
257 const ExplodedNode *PrevN,
Ted Kremenek53500662009-07-22 17:55:28 +0000258 BugReporterContext& BRC) {
259 if (isSatisfied)
260 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000261
Ted Kremenek53500662009-07-22 17:55:28 +0000262 // Check if in the previous state it was feasible for this constraint
263 // to *not* be true.
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000264 if (PrevN->getState()->Assume(Constraint, !Assumption)) {
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000265
Ted Kremenek53500662009-07-22 17:55:28 +0000266 isSatisfied = true;
Mike Stump1eb44332009-09-09 15:08:12 +0000267
Ted Kremenek53500662009-07-22 17:55:28 +0000268 // As a sanity check, make sure that the negation of the constraint
269 // was infeasible in the current state. If it is feasible, we somehow
270 // missed the transition point.
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000271 if (N->getState()->Assume(Constraint, !Assumption))
Ted Kremenek53500662009-07-22 17:55:28 +0000272 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000273
Ted Kremenek53500662009-07-22 17:55:28 +0000274 // We found the transition point for the constraint. We now need to
Mike Stump1eb44332009-09-09 15:08:12 +0000275 // pretty-print the constraint. (work-in-progress)
Daniel Dunbar0f2c9072010-03-20 04:28:39 +0000276 std::string sbuf;
277 llvm::raw_string_ostream os(sbuf);
Mike Stump1eb44332009-09-09 15:08:12 +0000278
Ted Kremenek53500662009-07-22 17:55:28 +0000279 if (isa<Loc>(Constraint)) {
280 os << "Assuming pointer value is ";
281 os << (Assumption ? "non-null" : "null");
282 }
Mike Stump1eb44332009-09-09 15:08:12 +0000283
Ted Kremenek53500662009-07-22 17:55:28 +0000284 if (os.str().empty())
285 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000286
Ted Kremenek53500662009-07-22 17:55:28 +0000287 // FIXME: Refactor this into BugReporterContext.
Mike Stump1eb44332009-09-09 15:08:12 +0000288 const Stmt *S = 0;
Ted Kremenek53500662009-07-22 17:55:28 +0000289 ProgramPoint P = N->getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000290
Ted Kremenek53500662009-07-22 17:55:28 +0000291 if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
292 CFGBlock *BSrc = BE->getSrc();
293 S = BSrc->getTerminatorCondition();
294 }
295 else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
296 S = PS->getStmt();
297 }
Mike Stump1eb44332009-09-09 15:08:12 +0000298
Ted Kremenek53500662009-07-22 17:55:28 +0000299 if (!S)
300 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000301
Ted Kremenek53500662009-07-22 17:55:28 +0000302 // Construct a new PathDiagnosticPiece.
303 PathDiagnosticLocation L(S, BRC.getSourceManager());
304 return new PathDiagnosticEventPiece(L, os.str());
305 }
Mike Stump1eb44332009-09-09 15:08:12 +0000306
Ted Kremenek53500662009-07-22 17:55:28 +0000307 return NULL;
Mike Stump1eb44332009-09-09 15:08:12 +0000308 }
Ted Kremenek53500662009-07-22 17:55:28 +0000309};
310} // end anonymous namespace
311
Ted Kremenek5b9bd212009-09-11 22:07:28 +0000312static void registerTrackConstraint(BugReporterContext& BRC,
313 DefinedSVal Constraint,
Ted Kremenek53500662009-07-22 17:55:28 +0000314 bool Assumption) {
Mike Stump1eb44332009-09-09 15:08:12 +0000315 BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
Ted Kremenek53500662009-07-22 17:55:28 +0000316}
317
318void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
Ted Kremenek592362b2009-08-18 01:05:30 +0000319 const void *data,
Zhongxing Xuc5619d92009-08-06 01:32:16 +0000320 const ExplodedNode* N) {
Mike Stump1eb44332009-09-09 15:08:12 +0000321
Ted Kremenek592362b2009-08-18 01:05:30 +0000322 const Stmt *S = static_cast<const Stmt*>(data);
Mike Stump1eb44332009-09-09 15:08:12 +0000323
Ted Kremenek53500662009-07-22 17:55:28 +0000324 if (!S)
325 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000326
Ted Kremenek53500662009-07-22 17:55:28 +0000327 GRStateManager &StateMgr = BRC.getStateManager();
Mike Stump1eb44332009-09-09 15:08:12 +0000328 const GRState *state = N->getState();
329
330 if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
331 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
Ted Kremenek53500662009-07-22 17:55:28 +0000332 const VarRegion *R =
Ted Kremenekd17da2b2009-08-21 22:28:32 +0000333 StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
Mike Stump1eb44332009-09-09 15:08:12 +0000334
Ted Kremenek53500662009-07-22 17:55:28 +0000335 // What did we load?
Ted Kremenek13976632010-02-08 16:18:51 +0000336 SVal V = state->getSVal(S);
Mike Stump1eb44332009-09-09 15:08:12 +0000337
338 if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
Ted Kremenek53500662009-07-22 17:55:28 +0000339 || V.isUndef()) {
Ted Kremenek94fd0b82010-02-16 08:33:59 +0000340 ::registerFindLastStore(BRC, R, V);
Ted Kremenek53500662009-07-22 17:55:28 +0000341 }
342 }
343 }
Mike Stump1eb44332009-09-09 15:08:12 +0000344
Ted Kremenek13976632010-02-08 16:18:51 +0000345 SVal V = state->getSValAsScalarOrLoc(S);
Mike Stump1eb44332009-09-09 15:08:12 +0000346
Ted Kremenek53500662009-07-22 17:55:28 +0000347 // Uncomment this to find cases where we aren't properly getting the
348 // base value that was dereferenced.
349 // assert(!V.isUnknownOrUndef());
Mike Stump1eb44332009-09-09 15:08:12 +0000350
Ted Kremenek53500662009-07-22 17:55:28 +0000351 // Is it a symbolic value?
352 if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
353 const SubRegion *R = cast<SubRegion>(L->getRegion());
354 while (R && !isa<SymbolicRegion>(R)) {
355 R = dyn_cast<SubRegion>(R->getSuperRegion());
356 }
Mike Stump1eb44332009-09-09 15:08:12 +0000357
Ted Kremenek53500662009-07-22 17:55:28 +0000358 if (R) {
359 assert(isa<SymbolicRegion>(R));
360 registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
361 }
362 }
363}
Ted Kremenek94fd0b82010-02-16 08:33:59 +0000364
365void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC,
366 const void *data,
367 const ExplodedNode* N) {
368
369 const MemRegion *R = static_cast<const MemRegion*>(data);
370
371 if (!R)
372 return;
373
374 const GRState *state = N->getState();
375 SVal V = state->getSVal(R);
376
377 if (V.isUnknown())
378 return;
379
380 BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
381}