1 //=== UndefBranchChecker.cpp -----------------------------------*- 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 UndefBranchChecker, which checks for undefined branch
13 //===----------------------------------------------------------------------===//
15 #include "InternalChecks.h"
16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h"
19 using namespace clang
;
24 class UndefBranchChecker
: public Checker
{
27 struct FindUndefExpr
{
31 FindUndefExpr(GRStateManager
& V
, const GRState
* S
) : VM(V
), St(S
) {}
33 const Expr
* FindExpr(const Expr
* Ex
) {
34 if (!MatchesCriteria(Ex
))
37 for (Stmt::const_child_iterator I
= Ex
->child_begin(),
38 E
= Ex
->child_end();I
!=E
;++I
)
39 if (const Expr
* ExI
= dyn_cast_or_null
<Expr
>(*I
)) {
40 const Expr
* E2
= FindExpr(ExI
);
47 bool MatchesCriteria(const Expr
* Ex
) { return St
->getSVal(Ex
).isUndef(); }
51 UndefBranchChecker() : BT(0) {}
52 static void *getTag();
53 void VisitBranchCondition(BranchNodeBuilder
&Builder
, ExprEngine
&Eng
,
54 const Stmt
*Condition
, void *tag
);
59 void ento::RegisterUndefBranchChecker(ExprEngine
&Eng
) {
60 Eng
.registerCheck(new UndefBranchChecker());
63 void *UndefBranchChecker::getTag() {
68 void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder
&Builder
,
70 const Stmt
*Condition
, void *tag
){
71 const GRState
*state
= Builder
.getState();
72 SVal X
= state
->getSVal(Condition
);
74 ExplodedNode
*N
= Builder
.generateNode(state
, true);
78 BT
= new BuiltinBug("Branch condition evaluates to a garbage value");
80 // What's going on here: we want to highlight the subexpression of the
81 // condition that is the most likely source of the "uninitialized
82 // branch condition." We do a recursive walk of the condition's
83 // subexpressions and roughly look for the most nested subexpression
84 // that binds to Undefined. We then highlight that expression's range.
85 BlockEdge B
= cast
<BlockEdge
>(N
->getLocation());
86 const Expr
* Ex
= cast
<Expr
>(B
.getSrc()->getTerminatorCondition());
87 assert (Ex
&& "Block must have a terminator.");
89 // Get the predecessor node and check if is a PostStmt with the Stmt
90 // being the terminator condition. We want to inspect the state
91 // of that node instead because it will contain main information about
92 // the subexpressions.
93 assert (!N
->pred_empty());
95 // Note: any predecessor will do. They should have identical state,
96 // since all the BlockEdge did was act as an error sink since the value
97 // had to already be undefined.
98 ExplodedNode
*PrevN
= *N
->pred_begin();
99 ProgramPoint P
= PrevN
->getLocation();
100 const GRState
* St
= N
->getState();
102 if (PostStmt
* PS
= dyn_cast
<PostStmt
>(&P
))
103 if (PS
->getStmt() == Ex
)
104 St
= PrevN
->getState();
106 FindUndefExpr
FindIt(Eng
.getStateManager(), St
);
107 Ex
= FindIt
.FindExpr(Ex
);
109 // Emit the bug report.
110 EnhancedBugReport
*R
= new EnhancedBugReport(*BT
, BT
->getDescription(),N
);
111 R
->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue
, Ex
);
112 R
->addRange(Ex
->getSourceRange());
114 Eng
.getBugReporter().EmitReport(R
);
117 Builder
.markInfeasible(true);
118 Builder
.markInfeasible(false);