UndefBranchChecker.cpp revision 04291a7c76e16a2dc5433c80c3d13c826bf372dc
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 "InternalChecks.h"
16#include "clang/StaticAnalyzer/BugReporter/BugType.h"
17#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
18
19using namespace clang;
20using namespace ento;
21
22namespace {
23
24class UndefBranchChecker : public Checker {
25  BuiltinBug *BT;
26
27  struct FindUndefExpr {
28    GRStateManager& VM;
29    const GRState* St;
30
31    FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
32
33    const Expr* FindExpr(const Expr* Ex) {
34      if (!MatchesCriteria(Ex))
35        return 0;
36
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);
41          if (E2) return E2;
42        }
43
44      return Ex;
45    }
46
47    bool MatchesCriteria(const Expr* Ex) { return St->getSVal(Ex).isUndef(); }
48  };
49
50public:
51  UndefBranchChecker() : BT(0) {}
52  static void *getTag();
53  void VisitBranchCondition(BranchNodeBuilder &Builder, ExprEngine &Eng,
54                            const Stmt *Condition, void *tag);
55};
56
57}
58
59void ento::RegisterUndefBranchChecker(ExprEngine &Eng) {
60  Eng.registerCheck(new UndefBranchChecker());
61}
62
63void *UndefBranchChecker::getTag() {
64  static int x;
65  return &x;
66}
67
68void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder,
69                                              ExprEngine &Eng,
70                                              const Stmt *Condition, void *tag){
71  const GRState *state = Builder.getState();
72  SVal X = state->getSVal(Condition);
73  if (X.isUndef()) {
74    ExplodedNode *N = Builder.generateNode(state, true);
75    if (N) {
76      N->markAsSink();
77      if (!BT)
78        BT = new BuiltinBug("Branch condition evaluates to a garbage value");
79
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.");
88
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());
94
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();
101
102      if (PostStmt* PS = dyn_cast<PostStmt>(&P))
103        if (PS->getStmt() == Ex)
104          St = PrevN->getState();
105
106      FindUndefExpr FindIt(Eng.getStateManager(), St);
107      Ex = FindIt.FindExpr(Ex);
108
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());
113
114      Eng.getBugReporter().EmitReport(R);
115    }
116
117    Builder.markInfeasible(true);
118    Builder.markInfeasible(false);
119  }
120}
121