UndefBranchChecker.cpp revision a19f4af7a94835ce4693bfe12d6270754e79eb56
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 21using namespace clang; 22using namespace ento; 23 24namespace { 25 26class 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 51public: 52 void checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder, 53 ExprEngine &Eng) const; 54}; 55 56} 57 58void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, 59 BranchNodeBuilder &Builder, 60 ExprEngine &Eng) const { 61 const ProgramState *state = Builder.getState(); 62 SVal X = state->getSVal(Condition); 63 if (X.isUndef()) { 64 // Generate a sink node. 65 ExplodedNode *N = Builder.generateNode(Condition, state, 0, true); 66 if (N) { 67 if (!BT) 68 BT.reset( 69 new BuiltinBug("Branch condition evaluates to a garbage value")); 70 71 // What's going on here: we want to highlight the subexpression of the 72 // condition that is the most likely source of the "uninitialized 73 // branch condition." We do a recursive walk of the condition's 74 // subexpressions and roughly look for the most nested subexpression 75 // that binds to Undefined. We then highlight that expression's range. 76 77 // Get the predecessor node and check if is a PostStmt with the Stmt 78 // being the terminator condition. We want to inspect the state 79 // of that node instead because it will contain main information about 80 // the subexpressions. 81 82 // Note: any predecessor will do. They should have identical state, 83 // since all the BlockEdge did was act as an error sink since the value 84 // had to already be undefined. 85 assert (!N->pred_empty()); 86 const Expr *Ex = cast<Expr>(Condition); 87 ExplodedNode *PrevN = *N->pred_begin(); 88 ProgramPoint P = PrevN->getLocation(); 89 const ProgramState *St = N->getState(); 90 91 if (PostStmt *PS = dyn_cast<PostStmt>(&P)) 92 if (PS->getStmt() == Ex) 93 St = PrevN->getState(); 94 95 FindUndefExpr FindIt(St); 96 Ex = FindIt.FindExpr(Ex); 97 98 // Emit the bug report. 99 BugReport *R = new BugReport(*BT, BT->getDescription(), N); 100 R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex)); 101 R->addRange(Ex->getSourceRange()); 102 103 Eng.getBugReporter().EmitReport(R); 104 } 105 106 Builder.markInfeasible(true); 107 Builder.markInfeasible(false); 108 } 109} 110 111void ento::registerUndefBranchChecker(CheckerManager &mgr) { 112 mgr.registerChecker<UndefBranchChecker>(); 113} 114