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