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