 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
63.0% |
87 / 138 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
87.0% |
120 / 138 |
| |
|
Line Coverage: |
76.5% |
127 / 166 |
| |
 |
|
 |
1 : // 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"
17 : #include "clang/Checker/BugReporter/BugReporter.h"
18 : #include "clang/Checker/BugReporter/PathDiagnostic.h"
19 : #include "clang/Checker/PathSensitive/GRState.h"
20 :
21 : using namespace clang;
22 :
23 : //===----------------------------------------------------------------------===//
24 : // Utility functions.
25 : //===----------------------------------------------------------------------===//
26 :
27 84: const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
28 : // Pattern match for a few useful cases (do something smarter later):
29 : // a[0], p->f, *p
30 84: const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
31 :
70: branch 1 taken
14: branch 2 taken
32 84: if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
70: branch 1 taken
0: branch 2 not taken
33 70: if (U->getOpcode() == UnaryOperator::Deref)
34 70: return U->getSubExpr()->IgnoreParenCasts();
35 : }
4: branch 1 taken
10: branch 2 taken
36 14: else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
37 4: return ME->getBase()->IgnoreParenCasts();
38 : }
10: branch 1 taken
0: branch 2 not taken
39 10: 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 10: return AE->getBase();
43 : }
44 :
45 0: return NULL;
46 : }
47 :
48 : const Stmt*
49 0: clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
50 0: const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
0: branch 1 not taken
0: branch 2 not taken
51 0: if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
52 0: return ME->getReceiver();
53 0: return NULL;
54 : }
55 :
56 : const Stmt*
57 0: clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
58 0: const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
0: branch 1 not taken
0: branch 2 not taken
59 0: if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
60 0: return BE->getRHS();
61 0: return NULL;
62 : }
63 :
64 : const Stmt*
65 0: clang::bugreporter::GetCalleeExpr(const ExplodedNode *N) {
66 : // Callee is checked as a PreVisit to the CallExpr.
67 0: const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
0: branch 1 not taken
0: branch 2 not taken
68 0: if (const CallExpr *CE = dyn_cast<CallExpr>(S))
69 0: return CE->getCallee();
70 0: return NULL;
71 : }
72 :
73 : const Stmt*
74 0: clang::bugreporter::GetRetValExpr(const ExplodedNode *N) {
75 0: const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
0: branch 1 not taken
0: branch 2 not taken
76 0: if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
77 0: return RS->getRetValue();
78 0: return NULL;
79 : }
80 :
81 : //===----------------------------------------------------------------------===//
82 : // Definitions for bug reporter visitors.
83 : //===----------------------------------------------------------------------===//
84 :
85 : namespace {
170: branch 2 taken
0: branch 3 not taken
0: branch 7 not taken
0: branch 8 not taken
86 170: class FindLastStoreBRVisitor : public BugReporterVisitor {
87 : const MemRegion *R;
88 : SVal V;
89 : bool satisfied;
90 : const ExplodedNode *StoreSite;
91 : public:
92 170: FindLastStoreBRVisitor(SVal v, const MemRegion *r)
93 170: : R(r), V(v), satisfied(false), StoreSite(0) {}
94 :
95 : PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
96 : const ExplodedNode *PrevN,
97 1472: BugReporterContext& BRC) {
98 :
550: branch 0 taken
922: branch 1 taken
99 1472: if (satisfied)
100 550: return NULL;
101 :
170: branch 0 taken
752: branch 1 taken
102 922: if (!StoreSite) {
103 170: const ExplodedNode *Node = N, *Last = NULL;
104 :
947: branch 1 taken
2: branch 2 taken
105 949: for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
106 :
947: branch 1 taken
0: branch 2 not taken
107 947: if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
825: branch 1 taken
122: branch 2 taken
108 947: if (const PostStmt *P = Node->getLocationAs<PostStmt>())
180: branch 1 taken
645: branch 2 taken
109 825: if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
160: branch 2 taken
20: branch 3 taken
110 180: if (DS->getSingleDecl() == VR->getDecl()) {
111 160: Last = Node;
112 160: break;
113 : }
114 : }
115 :
8: branch 4 taken
779: branch 5 taken
116 787: if (Node->getState()->getSVal(R) != V)
117 8: break;
118 : }
119 :
168: branch 0 taken
2: branch 1 taken
0: branch 2 not taken
168: branch 3 taken
120 170: if (!Node || !Last) {
121 2: satisfied = true;
122 2: return NULL;
123 : }
124 :
125 168: StoreSite = Last;
126 : }
127 :
752: branch 0 taken
168: branch 1 taken
128 920: if (StoreSite != N)
129 752: return NULL;
130 :
131 168: satisfied = true;
132 168: std::string sbuf;
133 168: llvm::raw_string_ostream os(sbuf);
134 :
168: branch 1 taken
0: branch 2 not taken
135 168: if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
160: branch 1 taken
8: branch 2 taken
136 168: if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
137 :
160: branch 1 taken
0: branch 2 not taken
138 160: if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
139 160: os << "Variable '" << VR->getDecl()->getNameAsString() << "' ";
140 : }
141 : else
142 0: return NULL;
143 :
47: branch 1 taken
113: branch 2 taken
144 160: if (isa<loc::ConcreteInt>(V)) {
145 47: bool b = false;
146 47: ASTContext &C = BRC.getASTContext();
47: branch 1 taken
0: branch 2 not taken
147 47: if (R->isBoundable()) {
47: branch 1 taken
0: branch 2 not taken
148 47: if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
8: branch 3 taken
39: branch 4 taken
149 47: if (TR->getValueType(C)->isObjCObjectPointerType()) {
150 8: os << "initialized to nil";
151 8: b = true;
152 : }
153 : }
154 : }
155 :
39: branch 0 taken
8: branch 1 taken
156 47: if (!b)
157 39: os << "initialized to a null pointer value";
158 : }
0: branch 1 not taken
113: branch 2 taken
159 113: else if (isa<nonloc::ConcreteInt>(V)) {
160 0: os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
161 : }
113: branch 1 taken
0: branch 2 not taken
162 113: else if (V.isUndef()) {
113: branch 1 taken
0: branch 2 not taken
163 113: if (isa<VarRegion>(R)) {
164 113: const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
0: branch 1 not taken
113: branch 2 taken
165 113: if (VD->getInit())
166 0: os << "initialized to a garbage value";
167 : else
168 113: os << "declared without an initial value";
169 : }
170 : }
171 : }
172 : }
173 :
8: branch 2 taken
160: branch 3 taken
174 168: if (os.str().empty()) {
8: branch 1 taken
0: branch 2 not taken
175 8: if (isa<loc::ConcreteInt>(V)) {
176 8: bool b = false;
177 8: ASTContext &C = BRC.getASTContext();
8: branch 1 taken
0: branch 2 not taken
178 8: if (R->isBoundable()) {
8: branch 1 taken
0: branch 2 not taken
179 8: if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
2: branch 3 taken
6: branch 4 taken
180 8: if (TR->getValueType(C)->isObjCObjectPointerType()) {
181 2: os << "nil object reference stored to ";
182 2: b = true;
183 : }
184 : }
185 : }
186 :
6: branch 0 taken
2: branch 1 taken
187 8: if (!b)
188 6: os << "Null pointer value stored to ";
189 : }
0: branch 1 not taken
0: branch 2 not taken
190 0: else if (V.isUndef()) {
191 0: os << "Uninitialized value stored to ";
192 : }
0: branch 1 not taken
0: branch 2 not taken
193 0: else if (isa<nonloc::ConcreteInt>(V)) {
194 : os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
195 0: << " is assigned to ";
196 : }
197 : else
198 0: return NULL;
199 :
8: branch 1 taken
0: branch 2 not taken
200 8: if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
201 8: os << '\'' << VR->getDecl()->getNameAsString() << '\'';
202 : }
203 : else
204 0: return NULL;
205 : }
206 :
207 : // FIXME: Refactor this into BugReporterContext.
208 168: const Stmt *S = 0;
209 168: ProgramPoint P = N->getLocation();
210 :
0: branch 1 not taken
168: branch 2 taken
211 168: if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
212 0: CFGBlock *BSrc = BE->getSrc();
213 0: S = BSrc->getTerminatorCondition();
214 : }
168: branch 1 taken
0: branch 2 not taken
215 168: else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
216 168: S = PS->getStmt();
217 : }
218 :
0: branch 0 not taken
168: branch 1 taken
219 168: if (!S)
220 0: return NULL;
221 :
222 : // Construct a new PathDiagnosticPiece.
223 168: PathDiagnosticLocation L(S, BRC.getSourceManager());
224 168: return new PathDiagnosticEventPiece(L, os.str());
225 : }
226 : };
227 :
228 :
229 : static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
230 170: SVal V) {
231 170: BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
232 170: }
233 :
42: branch 2 taken
0: branch 3 not taken
0: branch 7 not taken
0: branch 8 not taken
234 42: class TrackConstraintBRVisitor : public BugReporterVisitor {
235 : DefinedSVal Constraint;
236 : const bool Assumption;
237 : bool isSatisfied;
238 : public:
239 42: TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
240 42: : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
241 :
242 : PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
243 : const ExplodedNode *PrevN,
244 437: BugReporterContext& BRC) {
148: branch 0 taken
289: branch 1 taken
245 437: if (isSatisfied)
246 148: return NULL;
247 :
248 : // Check if in the previous state it was feasible for this constraint
249 : // to *not* be true.
42: branch 3 taken
247: branch 4 taken
250 289: if (PrevN->getState()->Assume(Constraint, !Assumption)) {
251 :
252 42: isSatisfied = true;
253 :
254 : // As a sanity check, make sure that the negation of the constraint
255 : // was infeasible in the current state. If it is feasible, we somehow
256 : // missed the transition point.
0: branch 3 not taken
42: branch 4 taken
257 42: if (N->getState()->Assume(Constraint, !Assumption))
258 0: return NULL;
259 :
260 : // We found the transition point for the constraint. We now need to
261 : // pretty-print the constraint. (work-in-progress)
262 42: std::string sbuf;
263 42: llvm::raw_string_ostream os(sbuf);
264 :
42: branch 1 taken
0: branch 2 not taken
265 42: if (isa<Loc>(Constraint)) {
266 42: os << "Assuming pointer value is ";
0: branch 0 not taken
42: branch 1 taken
267 42: os << (Assumption ? "non-null" : "null");
268 : }
269 :
0: branch 2 not taken
42: branch 3 taken
270 42: if (os.str().empty())
271 0: return NULL;
272 :
273 : // FIXME: Refactor this into BugReporterContext.
274 42: const Stmt *S = 0;
275 42: ProgramPoint P = N->getLocation();
276 :
42: branch 1 taken
0: branch 2 not taken
277 42: if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
278 42: CFGBlock *BSrc = BE->getSrc();
279 42: S = BSrc->getTerminatorCondition();
280 : }
0: branch 1 not taken
0: branch 2 not taken
281 0: else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
282 0: S = PS->getStmt();
283 : }
284 :
0: branch 0 not taken
42: branch 1 taken
285 42: if (!S)
286 0: return NULL;
287 :
288 : // Construct a new PathDiagnosticPiece.
289 42: PathDiagnosticLocation L(S, BRC.getSourceManager());
290 42: return new PathDiagnosticEventPiece(L, os.str());
291 : }
292 :
293 247: return NULL;
294 : }
295 : };
296 : } // end anonymous namespace
297 :
298 : static void registerTrackConstraint(BugReporterContext& BRC,
299 : DefinedSVal Constraint,
300 42: bool Assumption) {
301 42: BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
302 42: }
303 :
304 : void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
305 : const void *data,
306 237: const ExplodedNode* N) {
307 :
308 237: const Stmt *S = static_cast<const Stmt*>(data);
309 :
0: branch 0 not taken
237: branch 1 taken
310 237: if (!S)
311 0: return;
312 :
313 237: GRStateManager &StateMgr = BRC.getStateManager();
314 237: const GRState *state = N->getState();
315 :
222: branch 1 taken
15: branch 2 taken
316 237: if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
222: branch 2 taken
0: branch 3 not taken
317 222: if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
318 : const VarRegion *R =
319 222: StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
320 :
321 : // What did we load?
322 222: SVal V = state->getSVal(S);
323 :
167: branch 1 taken
55: branch 2 taken
167: branch 4 taken
0: branch 5 not taken
115: branch 7 taken
52: branch 8 taken
170: branch 9 taken
52: branch 10 taken
324 222: if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
325 : || V.isUndef()) {
326 170: registerFindLastStore(BRC, R, V);
327 222: }
328 : }
329 : }
330 :
331 237: SVal V = state->getSValAsScalarOrLoc(S);
332 :
333 : // Uncomment this to find cases where we aren't properly getting the
334 : // base value that was dereferenced.
335 : // assert(!V.isUnknownOrUndef());
336 :
337 : // Is it a symbolic value?
42: branch 1 taken
195: branch 2 taken
338 237: if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
339 42: const SubRegion *R = cast<SubRegion>(L->getRegion());
46: branch 0 taken
0: branch 1 not taken
4: branch 3 taken
42: branch 4 taken
4: branch 5 taken
42: branch 6 taken
340 88: while (R && !isa<SymbolicRegion>(R)) {
341 4: R = dyn_cast<SubRegion>(R->getSuperRegion());
342 : }
343 :
42: branch 0 taken
0: branch 1 not taken
344 42: if (R) {
0: branch 1 not taken
42: branch 2 taken
345 42: assert(isa<SymbolicRegion>(R));
346 42: registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
347 : }
348 237: }
349 : }
Generated: 2010-02-10 01:31 by zcov