1 // BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- C++ -*--//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines a set of BugReporter "visitors" which can be used to
11 // enhance the diagnostics reported for a bug.
13 //===----------------------------------------------------------------------===//
15 #include "clang/AST/Expr.h"
16 #include "clang/AST/ExprObjC.h"
17 #include "clang/GR/BugReporter/BugReporter.h"
18 #include "clang/GR/BugReporter/PathDiagnostic.h"
19 #include "clang/GR/PathSensitive/ExplodedGraph.h"
20 #include "clang/GR/PathSensitive/GRState.h"
22 using namespace clang
;
25 //===----------------------------------------------------------------------===//
27 //===----------------------------------------------------------------------===//
29 const Stmt
*bugreporter::GetDerefExpr(const ExplodedNode
*N
) {
30 // Pattern match for a few useful cases (do something smarter later):
32 const Stmt
*S
= N
->getLocationAs
<PostStmt
>()->getStmt();
34 if (const UnaryOperator
*U
= dyn_cast
<UnaryOperator
>(S
)) {
35 if (U
->getOpcode() == UO_Deref
)
36 return U
->getSubExpr()->IgnoreParenCasts();
38 else if (const MemberExpr
*ME
= dyn_cast
<MemberExpr
>(S
)) {
39 return ME
->getBase()->IgnoreParenCasts();
41 else if (const ArraySubscriptExpr
*AE
= dyn_cast
<ArraySubscriptExpr
>(S
)) {
42 // Retrieve the base for arrays since BasicStoreManager doesn't know how
43 // to reason about them.
50 const Stmt
*bugreporter::GetDenomExpr(const ExplodedNode
*N
) {
51 const Stmt
*S
= N
->getLocationAs
<PreStmt
>()->getStmt();
52 if (const BinaryOperator
*BE
= dyn_cast
<BinaryOperator
>(S
))
57 const Stmt
*bugreporter::GetCalleeExpr(const ExplodedNode
*N
) {
58 // Callee is checked as a PreVisit to the CallExpr.
59 const Stmt
*S
= N
->getLocationAs
<PreStmt
>()->getStmt();
60 if (const CallExpr
*CE
= dyn_cast
<CallExpr
>(S
))
61 return CE
->getCallee();
65 const Stmt
*bugreporter::GetRetValExpr(const ExplodedNode
*N
) {
66 const Stmt
*S
= N
->getLocationAs
<PostStmt
>()->getStmt();
67 if (const ReturnStmt
*RS
= dyn_cast
<ReturnStmt
>(S
))
68 return RS
->getRetValue();
72 //===----------------------------------------------------------------------===//
73 // Definitions for bug reporter visitors.
74 //===----------------------------------------------------------------------===//
77 class FindLastStoreBRVisitor
: public BugReporterVisitor
{
81 const ExplodedNode
*StoreSite
;
83 FindLastStoreBRVisitor(SVal v
, const MemRegion
*r
)
84 : R(r
), V(v
), satisfied(false), StoreSite(0) {}
86 virtual void Profile(llvm::FoldingSetNodeID
&ID
) const {
93 PathDiagnosticPiece
* VisitNode(const ExplodedNode
*N
,
94 const ExplodedNode
*PrevN
,
95 BugReporterContext
& BRC
) {
101 const ExplodedNode
*Node
= N
, *Last
= NULL
;
103 for ( ; Node
; Last
= Node
, Node
= Node
->getFirstPred()) {
105 if (const VarRegion
*VR
= dyn_cast
<VarRegion
>(R
)) {
106 if (const PostStmt
*P
= Node
->getLocationAs
<PostStmt
>())
107 if (const DeclStmt
*DS
= P
->getStmtAs
<DeclStmt
>())
108 if (DS
->getSingleDecl() == VR
->getDecl()) {
114 if (Node
->getState()->getSVal(R
) != V
)
118 if (!Node
|| !Last
) {
130 llvm::SmallString
<256> sbuf
;
131 llvm::raw_svector_ostream
os(sbuf
);
133 if (const PostStmt
*PS
= N
->getLocationAs
<PostStmt
>()) {
134 if (const DeclStmt
*DS
= PS
->getStmtAs
<DeclStmt
>()) {
136 if (const VarRegion
*VR
= dyn_cast
<VarRegion
>(R
)) {
137 os
<< "Variable '" << VR
->getDecl() << "' ";
142 if (isa
<loc::ConcreteInt
>(V
)) {
144 if (R
->isBoundable()) {
145 if (const TypedRegion
*TR
= dyn_cast
<TypedRegion
>(R
)) {
146 if (TR
->getValueType()->isObjCObjectPointerType()) {
147 os
<< "initialized to nil";
154 os
<< "initialized to a null pointer value";
156 else if (isa
<nonloc::ConcreteInt
>(V
)) {
157 os
<< "initialized to " << cast
<nonloc::ConcreteInt
>(V
).getValue();
159 else if (V
.isUndef()) {
160 if (isa
<VarRegion
>(R
)) {
161 const VarDecl
*VD
= cast
<VarDecl
>(DS
->getSingleDecl());
163 os
<< "initialized to a garbage value";
165 os
<< "declared without an initial value";
171 if (os
.str().empty()) {
172 if (isa
<loc::ConcreteInt
>(V
)) {
174 if (R
->isBoundable()) {
175 if (const TypedRegion
*TR
= dyn_cast
<TypedRegion
>(R
)) {
176 if (TR
->getValueType()->isObjCObjectPointerType()) {
177 os
<< "nil object reference stored to ";
184 os
<< "Null pointer value stored to ";
186 else if (V
.isUndef()) {
187 os
<< "Uninitialized value stored to ";
189 else if (isa
<nonloc::ConcreteInt
>(V
)) {
190 os
<< "The value " << cast
<nonloc::ConcreteInt
>(V
).getValue()
191 << " is assigned to ";
196 if (const VarRegion
*VR
= dyn_cast
<VarRegion
>(R
)) {
197 os
<< '\'' << VR
->getDecl() << '\'';
203 // FIXME: Refactor this into BugReporterContext.
205 ProgramPoint P
= N
->getLocation();
207 if (BlockEdge
*BE
= dyn_cast
<BlockEdge
>(&P
)) {
208 const CFGBlock
*BSrc
= BE
->getSrc();
209 S
= BSrc
->getTerminatorCondition();
211 else if (PostStmt
*PS
= dyn_cast
<PostStmt
>(&P
)) {
218 // Construct a new PathDiagnosticPiece.
219 PathDiagnosticLocation
L(S
, BRC
.getSourceManager());
220 return new PathDiagnosticEventPiece(L
, os
.str());
225 static void registerFindLastStore(BugReporterContext
& BRC
, const MemRegion
*R
,
227 BRC
.addVisitor(new FindLastStoreBRVisitor(V
, R
));
230 class TrackConstraintBRVisitor
: public BugReporterVisitor
{
231 DefinedSVal Constraint
;
232 const bool Assumption
;
235 TrackConstraintBRVisitor(DefinedSVal constraint
, bool assumption
)
236 : Constraint(constraint
), Assumption(assumption
), isSatisfied(false) {}
238 void Profile(llvm::FoldingSetNodeID
&ID
) const {
241 ID
.AddBoolean(Assumption
);
245 PathDiagnosticPiece
* VisitNode(const ExplodedNode
*N
,
246 const ExplodedNode
*PrevN
,
247 BugReporterContext
& BRC
) {
251 // Check if in the previous state it was feasible for this constraint
253 if (PrevN
->getState()->assume(Constraint
, !Assumption
)) {
257 // As a sanity check, make sure that the negation of the constraint
258 // was infeasible in the current state. If it is feasible, we somehow
259 // missed the transition point.
260 if (N
->getState()->assume(Constraint
, !Assumption
))
263 // We found the transition point for the constraint. We now need to
264 // pretty-print the constraint. (work-in-progress)
266 llvm::raw_string_ostream
os(sbuf
);
268 if (isa
<Loc
>(Constraint
)) {
269 os
<< "Assuming pointer value is ";
270 os
<< (Assumption
? "non-null" : "null");
273 if (os
.str().empty())
276 // FIXME: Refactor this into BugReporterContext.
278 ProgramPoint P
= N
->getLocation();
280 if (BlockEdge
*BE
= dyn_cast
<BlockEdge
>(&P
)) {
281 const CFGBlock
*BSrc
= BE
->getSrc();
282 S
= BSrc
->getTerminatorCondition();
284 else if (PostStmt
*PS
= dyn_cast
<PostStmt
>(&P
)) {
291 // Construct a new PathDiagnosticPiece.
292 PathDiagnosticLocation
L(S
, BRC
.getSourceManager());
293 return new PathDiagnosticEventPiece(L
, os
.str());
299 } // end anonymous namespace
301 static void registerTrackConstraint(BugReporterContext
& BRC
,
302 DefinedSVal Constraint
,
304 BRC
.addVisitor(new TrackConstraintBRVisitor(Constraint
, Assumption
));
307 void bugreporter::registerTrackNullOrUndefValue(BugReporterContext
& BRC
,
309 const ExplodedNode
* N
) {
311 const Stmt
*S
= static_cast<const Stmt
*>(data
);
316 GRStateManager
&StateMgr
= BRC
.getStateManager();
317 const GRState
*state
= N
->getState();
319 // Walk through lvalue-to-rvalue conversions.
320 if (const DeclRefExpr
*DR
= dyn_cast
<DeclRefExpr
>(S
)) {
321 if (const VarDecl
*VD
= dyn_cast
<VarDecl
>(DR
->getDecl())) {
323 StateMgr
.getRegionManager().getVarRegion(VD
, N
->getLocationContext());
326 SVal V
= state
->getSVal(loc::MemRegionVal(R
));
328 if (isa
<loc::ConcreteInt
>(V
) || isa
<nonloc::ConcreteInt
>(V
)
330 ::registerFindLastStore(BRC
, R
, V
);
335 SVal V
= state
->getSValAsScalarOrLoc(S
);
337 // Uncomment this to find cases where we aren't properly getting the
338 // base value that was dereferenced.
339 // assert(!V.isUnknownOrUndef());
341 // Is it a symbolic value?
342 if (loc::MemRegionVal
*L
= dyn_cast
<loc::MemRegionVal
>(&V
)) {
343 const SubRegion
*R
= cast
<SubRegion
>(L
->getRegion());
344 while (R
&& !isa
<SymbolicRegion
>(R
)) {
345 R
= dyn_cast
<SubRegion
>(R
->getSuperRegion());
349 assert(isa
<SymbolicRegion
>(R
));
350 registerTrackConstraint(BRC
, loc::MemRegionVal(R
), false);
355 void bugreporter::registerFindLastStore(BugReporterContext
& BRC
,
357 const ExplodedNode
* N
) {
359 const MemRegion
*R
= static_cast<const MemRegion
*>(data
);
364 const GRState
*state
= N
->getState();
365 SVal V
= state
->getSVal(R
);
370 BRC
.addVisitor(new FindLastStoreBRVisitor(V
, R
));
375 class NilReceiverVisitor
: public BugReporterVisitor
{
377 NilReceiverVisitor() {}
379 void Profile(llvm::FoldingSetNodeID
&ID
) const {
384 PathDiagnosticPiece
* VisitNode(const ExplodedNode
*N
,
385 const ExplodedNode
*PrevN
,
386 BugReporterContext
& BRC
) {
388 const PostStmt
*P
= N
->getLocationAs
<PostStmt
>();
391 const ObjCMessageExpr
*ME
= P
->getStmtAs
<ObjCMessageExpr
>();
394 const Expr
*Receiver
= ME
->getInstanceReceiver();
397 const GRState
*state
= N
->getState();
398 const SVal
&V
= state
->getSVal(Receiver
);
399 const DefinedOrUnknownSVal
*DV
= dyn_cast
<DefinedOrUnknownSVal
>(&V
);
402 state
= state
->assume(*DV
, true);
406 // The receiver was nil, and hence the method was skipped.
407 // Register a BugReporterVisitor to issue a message telling us how
408 // the receiver was null.
409 bugreporter::registerTrackNullOrUndefValue(BRC
, Receiver
, N
);
410 // Issue a message saying that the method was skipped.
411 PathDiagnosticLocation
L(Receiver
, BRC
.getSourceManager());
412 return new PathDiagnosticEventPiece(L
, "No method actually called "
413 "because the receiver is nil");
416 } // end anonymous namespace
418 void bugreporter::registerNilReceiverVisitor(BugReporterContext
&BRC
) {
419 BRC
.addVisitor(new NilReceiverVisitor());
422 // Registers every VarDecl inside a Stmt with a last store vistor.
423 void bugreporter::registerVarDeclsLastStore(BugReporterContext
&BRC
,
425 const ExplodedNode
*N
) {
426 const Stmt
*S
= static_cast<const Stmt
*>(stmt
);
428 std::deque
<const Stmt
*> WorkList
;
430 WorkList
.push_back(S
);
432 while (!WorkList
.empty()) {
433 const Stmt
*Head
= WorkList
.front();
434 WorkList
.pop_front();
436 GRStateManager
&StateMgr
= BRC
.getStateManager();
437 const GRState
*state
= N
->getState();
439 if (const DeclRefExpr
*DR
= dyn_cast
<DeclRefExpr
>(Head
)) {
440 if (const VarDecl
*VD
= dyn_cast
<VarDecl
>(DR
->getDecl())) {
442 StateMgr
.getRegionManager().getVarRegion(VD
, N
->getLocationContext());
445 SVal V
= state
->getSVal(S
);
447 if (isa
<loc::ConcreteInt
>(V
) || isa
<nonloc::ConcreteInt
>(V
)) {
448 ::registerFindLastStore(BRC
, R
, V
);
453 for (Stmt::const_child_iterator I
= Head
->child_begin();
454 I
!= Head
->child_end(); ++I
)
455 WorkList
.push_back(*I
);