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/BugReporter/BugType.h" 17 #include "clang/StaticAnalyzer/Core/Checker.h" 18 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20 21 using namespace clang; 22 using namespace ento; 23 24 namespace { 25 26 class UndefBranchChecker : public Checker<check::BranchCondition> { 27 mutable std::unique_ptr<BuiltinBug> BT; 28 29 struct FindUndefExpr { 30 ProgramStateRef St; 31 const LocationContext *LCtx; 32 33 FindUndefExpr(ProgramStateRef S, const LocationContext *L) 34 : St(S), LCtx(L) {} 35 36 const Expr *FindExpr(const Expr *Ex) { 37 if (!MatchesCriteria(Ex)) 38 return nullptr; 39 40 for (Stmt::const_child_iterator I = Ex->child_begin(), 41 E = Ex->child_end();I!=E;++I) 42 if (const Expr *ExI = dyn_cast_or_null<Expr>(*I)) { 43 const Expr *E2 = FindExpr(ExI); 44 if (E2) return E2; 45 } 46 47 return Ex; 48 } 49 50 bool MatchesCriteria(const Expr *Ex) { 51 return St->getSVal(Ex, LCtx).isUndef(); 52 } 53 }; 54 55 public: 56 void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const; 57 }; 58 59 } 60 61 void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, 62 CheckerContext &Ctx) const { 63 SVal X = Ctx.getState()->getSVal(Condition, Ctx.getLocationContext()); 64 if (X.isUndef()) { 65 // Generate a sink node, which implicitly marks both outgoing branches as 66 // infeasible. 67 ExplodedNode *N = Ctx.generateSink(); 68 if (N) { 69 if (!BT) 70 BT.reset(new BuiltinBug( 71 this, "Branch condition evaluates to a garbage value")); 72 73 // What's going on here: we want to highlight the subexpression of the 74 // condition that is the most likely source of the "uninitialized 75 // branch condition." We do a recursive walk of the condition's 76 // subexpressions and roughly look for the most nested subexpression 77 // that binds to Undefined. We then highlight that expression's range. 78 79 // Get the predecessor node and check if is a PostStmt with the Stmt 80 // being the terminator condition. We want to inspect the state 81 // of that node instead because it will contain main information about 82 // the subexpressions. 83 84 // Note: any predecessor will do. They should have identical state, 85 // since all the BlockEdge did was act as an error sink since the value 86 // had to already be undefined. 87 assert (!N->pred_empty()); 88 const Expr *Ex = cast<Expr>(Condition); 89 ExplodedNode *PrevN = *N->pred_begin(); 90 ProgramPoint P = PrevN->getLocation(); 91 ProgramStateRef St = N->getState(); 92 93 if (Optional<PostStmt> PS = P.getAs<PostStmt>()) 94 if (PS->getStmt() == Ex) 95 St = PrevN->getState(); 96 97 FindUndefExpr FindIt(St, Ctx.getLocationContext()); 98 Ex = FindIt.FindExpr(Ex); 99 100 // Emit the bug report. 101 BugReport *R = new BugReport(*BT, BT->getDescription(), N); 102 bugreporter::trackNullOrUndefValue(N, Ex, *R); 103 R->addRange(Ex->getSourceRange()); 104 105 Ctx.emitReport(R); 106 } 107 } 108 } 109 110 void ento::registerUndefBranchChecker(CheckerManager &mgr) { 111 mgr.registerChecker<UndefBranchChecker>(); 112 } 113