]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
Copy head to stable/9 as part of 9.0-RELEASE release cycle.
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / UndefBranchChecker.cpp
1 //=== UndefBranchChecker.cpp -----------------------------------*- 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 UndefBranchChecker, which checks for undefined branch
11 // condition.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "ClangSACheckers.h"
16 #include "clang/StaticAnalyzer/Core/Checker.h"
17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20
21 using namespace clang;
22 using namespace ento;
23
24 namespace {
25
26 class UndefBranchChecker : public Checker<check::BranchCondition> {
27   mutable llvm::OwningPtr<BuiltinBug> BT;
28
29   struct FindUndefExpr {
30     GRStateManager& VM;
31     const GRState* St;
32
33     FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
34
35     const Expr* FindExpr(const Expr* Ex) {
36       if (!MatchesCriteria(Ex))
37         return 0;
38
39       for (Stmt::const_child_iterator I = Ex->child_begin(), 
40                                       E = Ex->child_end();I!=E;++I)
41         if (const Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
42           const Expr* E2 = FindExpr(ExI);
43           if (E2) return E2;
44         }
45
46       return Ex;
47     }
48
49     bool MatchesCriteria(const Expr* Ex) { return St->getSVal(Ex).isUndef(); }
50   };
51
52 public:
53   void checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder,
54                             ExprEngine &Eng) const;
55 };
56
57 }
58
59 void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
60                                               BranchNodeBuilder &Builder,
61                                               ExprEngine &Eng) const {
62   const GRState *state = Builder.getState();
63   SVal X = state->getSVal(Condition);
64   if (X.isUndef()) {
65     ExplodedNode *N = Builder.generateNode(state, true);
66     if (N) {
67       N->markAsSink();
68       if (!BT)
69         BT.reset(
70                new BuiltinBug("Branch condition evaluates to a garbage value"));
71
72       // What's going on here: we want to highlight the subexpression of the
73       // condition that is the most likely source of the "uninitialized
74       // branch condition."  We do a recursive walk of the condition's
75       // subexpressions and roughly look for the most nested subexpression
76       // that binds to Undefined.  We then highlight that expression's range.
77       BlockEdge B = cast<BlockEdge>(N->getLocation());
78       const Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
79       assert (Ex && "Block must have a terminator.");
80
81       // Get the predecessor node and check if is a PostStmt with the Stmt
82       // being the terminator condition.  We want to inspect the state
83       // of that node instead because it will contain main information about
84       // the subexpressions.
85       assert (!N->pred_empty());
86
87       // Note: any predecessor will do.  They should have identical state,
88       // since all the BlockEdge did was act as an error sink since the value
89       // had to already be undefined.
90       ExplodedNode *PrevN = *N->pred_begin();
91       ProgramPoint P = PrevN->getLocation();
92       const GRState* St = N->getState();
93
94       if (PostStmt* PS = dyn_cast<PostStmt>(&P))
95         if (PS->getStmt() == Ex)
96           St = PrevN->getState();
97
98       FindUndefExpr FindIt(Eng.getStateManager(), St);
99       Ex = FindIt.FindExpr(Ex);
100
101       // Emit the bug report.
102       EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N);
103       R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
104       R->addRange(Ex->getSourceRange());
105
106       Eng.getBugReporter().EmitReport(R);
107     }
108
109     Builder.markInfeasible(true);
110     Builder.markInfeasible(false);
111   }
112 }
113
114 void ento::registerUndefBranchChecker(CheckerManager &mgr) {
115   mgr.registerChecker<UndefBranchChecker>();
116 }