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
FindUndefExpr__anon948439880111::UndefBranchChecker::FindUndefExpr33 FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
34
FindExpr__anon948439880111::UndefBranchChecker::FindUndefExpr35 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
MatchesCriteria__anon948439880111::UndefBranchChecker::FindUndefExpr49 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
checkBranchCondition(const Stmt * Condition,BranchNodeBuilder & Builder,ExprEngine & Eng) const59 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
registerUndefBranchChecker(CheckerManager & mgr)114 void ento::registerUndefBranchChecker(CheckerManager &mgr) {
115 mgr.registerChecker<UndefBranchChecker>();
116 }
117