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