xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp (revision d99bd55a5e092774214ba31fc5a871bfc31e711c)
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 "ExprEngineInternalChecks.h"
16 #include "clang/StaticAnalyzer/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/PathSensitive/Checker.h"
18 
19 using namespace clang;
20 using namespace ento;
21 
22 namespace {
23 
24 class 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 
50 public:
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 
59 void ento::RegisterUndefBranchChecker(ExprEngine &Eng) {
60   Eng.registerCheck(new UndefBranchChecker());
61 }
62 
63 void *UndefBranchChecker::getTag() {
64   static int x;
65   return &x;
66 }
67 
68 void 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