clang API Documentation
00001 //== TestAfterDivZeroChecker.cpp - Test after division by zero checker --*--==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This defines TestAfterDivZeroChecker, a builtin check that performs checks 00011 // for division by zero where the division occurs before comparison with zero. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00017 #include "clang/StaticAnalyzer/Core/Checker.h" 00018 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00020 #include "llvm/ADT/FoldingSet.h" 00021 00022 using namespace clang; 00023 using namespace ento; 00024 00025 namespace { 00026 00027 class ZeroState { 00028 private: 00029 SymbolRef ZeroSymbol; 00030 unsigned BlockID; 00031 const StackFrameContext *SFC; 00032 00033 public: 00034 ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC) 00035 : ZeroSymbol(S), BlockID(B), SFC(SFC) {} 00036 00037 const StackFrameContext *getStackFrameContext() const { return SFC; } 00038 00039 bool operator==(const ZeroState &X) const { 00040 return BlockID == X.BlockID && SFC == X.SFC && ZeroSymbol == X.ZeroSymbol; 00041 } 00042 00043 bool operator<(const ZeroState &X) const { 00044 if (BlockID != X.BlockID) 00045 return BlockID < X.BlockID; 00046 if (SFC != X.SFC) 00047 return SFC < X.SFC; 00048 return ZeroSymbol < X.ZeroSymbol; 00049 } 00050 00051 void Profile(llvm::FoldingSetNodeID &ID) const { 00052 ID.AddInteger(BlockID); 00053 ID.AddPointer(SFC); 00054 ID.AddPointer(ZeroSymbol); 00055 } 00056 }; 00057 00058 class DivisionBRVisitor : public BugReporterVisitorImpl<DivisionBRVisitor> { 00059 private: 00060 SymbolRef ZeroSymbol; 00061 const StackFrameContext *SFC; 00062 bool Satisfied; 00063 00064 public: 00065 DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC) 00066 : ZeroSymbol(ZeroSymbol), SFC(SFC), Satisfied(false) {} 00067 00068 void Profile(llvm::FoldingSetNodeID &ID) const override { 00069 ID.Add(ZeroSymbol); 00070 ID.Add(SFC); 00071 } 00072 00073 PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, 00074 const ExplodedNode *Pred, 00075 BugReporterContext &BRC, 00076 BugReport &BR) override; 00077 }; 00078 00079 class TestAfterDivZeroChecker 00080 : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition, 00081 check::EndFunction> { 00082 mutable std::unique_ptr<BuiltinBug> DivZeroBug; 00083 void reportBug(SVal Val, CheckerContext &C) const; 00084 00085 public: 00086 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; 00087 void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const; 00088 void checkEndFunction(CheckerContext &C) const; 00089 void setDivZeroMap(SVal Var, CheckerContext &C) const; 00090 bool hasDivZeroMap(SVal Var, const CheckerContext &C) const; 00091 bool isZero(SVal S, CheckerContext &C) const; 00092 }; 00093 } // end anonymous namespace 00094 00095 REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState) 00096 00097 PathDiagnosticPiece *DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, 00098 const ExplodedNode *Pred, 00099 BugReporterContext &BRC, 00100 BugReport &BR) { 00101 if (Satisfied) 00102 return nullptr; 00103 00104 const Expr *E = nullptr; 00105 00106 if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) 00107 if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) { 00108 BinaryOperator::Opcode Op = BO->getOpcode(); 00109 if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign || 00110 Op == BO_RemAssign) { 00111 E = BO->getRHS(); 00112 } 00113 } 00114 00115 if (!E) 00116 return nullptr; 00117 00118 ProgramStateRef State = Succ->getState(); 00119 SVal S = State->getSVal(E, Succ->getLocationContext()); 00120 if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) { 00121 Satisfied = true; 00122 00123 // Construct a new PathDiagnosticPiece. 00124 ProgramPoint P = Succ->getLocation(); 00125 PathDiagnosticLocation L = 00126 PathDiagnosticLocation::create(P, BRC.getSourceManager()); 00127 00128 if (!L.isValid() || !L.asLocation().isValid()) 00129 return nullptr; 00130 00131 return new PathDiagnosticEventPiece( 00132 L, "Division with compared value made here"); 00133 } 00134 00135 return nullptr; 00136 } 00137 00138 bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const { 00139 Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>(); 00140 00141 if (!DSV) 00142 return false; 00143 00144 ConstraintManager &CM = C.getConstraintManager(); 00145 return !CM.assume(C.getState(), *DSV, true); 00146 } 00147 00148 void TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &C) const { 00149 SymbolRef SR = Var.getAsSymbol(); 00150 if (!SR) 00151 return; 00152 00153 ProgramStateRef State = C.getState(); 00154 State = 00155 State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame())); 00156 C.addTransition(State); 00157 } 00158 00159 bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var, 00160 const CheckerContext &C) const { 00161 SymbolRef SR = Var.getAsSymbol(); 00162 if (!SR) 00163 return false; 00164 00165 ZeroState ZS(SR, C.getBlockID(), C.getStackFrame()); 00166 return C.getState()->contains<DivZeroMap>(ZS); 00167 } 00168 00169 void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const { 00170 if (ExplodedNode *N = C.generateSink(C.getState())) { 00171 if (!DivZeroBug) 00172 DivZeroBug.reset(new BuiltinBug(this, "Division by zero")); 00173 00174 BugReport *R = 00175 new BugReport(*DivZeroBug, "Value being compared against zero has " 00176 "already been used for division", 00177 N); 00178 00179 R->addVisitor(llvm::make_unique<DivisionBRVisitor>(Val.getAsSymbol(), 00180 C.getStackFrame())); 00181 C.emitReport(R); 00182 } 00183 } 00184 00185 void TestAfterDivZeroChecker::checkEndFunction(CheckerContext &C) const { 00186 ProgramStateRef State = C.getState(); 00187 00188 DivZeroMapTy DivZeroes = State->get<DivZeroMap>(); 00189 if (DivZeroes.isEmpty()) 00190 return; 00191 00192 DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>(); 00193 for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(), 00194 E = DivZeroes.end(); 00195 I != E; ++I) { 00196 ZeroState ZS = *I; 00197 if (ZS.getStackFrameContext() == C.getStackFrame()) 00198 DivZeroes = F.remove(DivZeroes, ZS); 00199 } 00200 C.addTransition(State->set<DivZeroMap>(DivZeroes)); 00201 } 00202 00203 void TestAfterDivZeroChecker::checkPreStmt(const BinaryOperator *B, 00204 CheckerContext &C) const { 00205 BinaryOperator::Opcode Op = B->getOpcode(); 00206 if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign || 00207 Op == BO_RemAssign) { 00208 SVal S = C.getSVal(B->getRHS()); 00209 00210 if (!isZero(S, C)) 00211 setDivZeroMap(S, C); 00212 } 00213 } 00214 00215 void TestAfterDivZeroChecker::checkBranchCondition(const Stmt *Condition, 00216 CheckerContext &C) const { 00217 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) { 00218 if (B->isComparisonOp()) { 00219 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS()); 00220 bool LRHS = true; 00221 if (!IntLiteral) { 00222 IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS()); 00223 LRHS = false; 00224 } 00225 00226 if (!IntLiteral || IntLiteral->getValue() != 0) 00227 return; 00228 00229 SVal Val = C.getSVal(LRHS ? B->getLHS() : B->getRHS()); 00230 if (hasDivZeroMap(Val, C)) 00231 reportBug(Val, C); 00232 } 00233 } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)) { 00234 if (U->getOpcode() == UO_LNot) { 00235 SVal Val; 00236 if (const ImplicitCastExpr *I = 00237 dyn_cast<ImplicitCastExpr>(U->getSubExpr())) 00238 Val = C.getSVal(I->getSubExpr()); 00239 00240 if (hasDivZeroMap(Val, C)) 00241 reportBug(Val, C); 00242 else { 00243 Val = C.getSVal(U->getSubExpr()); 00244 if (hasDivZeroMap(Val, C)) 00245 reportBug(Val, C); 00246 } 00247 } 00248 } else if (const ImplicitCastExpr *IE = 00249 dyn_cast<ImplicitCastExpr>(Condition)) { 00250 SVal Val = C.getSVal(IE->getSubExpr()); 00251 00252 if (hasDivZeroMap(Val, C)) 00253 reportBug(Val, C); 00254 else { 00255 SVal Val = C.getSVal(Condition); 00256 00257 if (hasDivZeroMap(Val, C)) 00258 reportBug(Val, C); 00259 } 00260 } 00261 } 00262 00263 void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) { 00264 mgr.registerChecker<TestAfterDivZeroChecker>(); 00265 }