19#include "llvm/ADT/FoldingSet.h"
31 const StackFrameContext *SFC;
34 ZeroState(
SymbolRef S,
unsigned B,
const StackFrameContext *SFC)
35 : ZeroSymbol(S), BlockID(B), SFC(SFC) {}
37 const StackFrameContext *getStackFrameContext()
const {
return SFC; }
40 return BlockID ==
X.BlockID && SFC ==
X.SFC && ZeroSymbol ==
X.ZeroSymbol;
44 return std::tie(BlockID, SFC, ZeroSymbol) <
45 std::tie(
X.BlockID,
X.SFC,
X.ZeroSymbol);
48 void Profile(llvm::FoldingSetNodeID &ID)
const {
49 ID.AddInteger(BlockID);
51 ID.AddPointer(ZeroSymbol);
58 const StackFrameContext *SFC;
62 DivisionBRVisitor(
SymbolRef ZeroSymbol,
const StackFrameContext *SFC)
63 : ZeroSymbol(ZeroSymbol), SFC(SFC), Satisfied(
false) {}
65 void Profile(llvm::FoldingSetNodeID &ID)
const override {
71 BugReporterContext &BRC,
72 PathSensitiveBugReport &BR)
override;
75class TestAfterDivZeroChecker
76 :
public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
78 const BugType DivZeroBug{
this,
"Division by zero"};
79 void reportBug(SVal Val, CheckerContext &
C)
const;
82 void checkPreStmt(
const BinaryOperator *B, CheckerContext &
C)
const;
83 void checkBranchCondition(
const Stmt *
Condition, CheckerContext &
C)
const;
84 void checkEndFunction(
const ReturnStmt *RS, CheckerContext &
C)
const;
85 void setDivZeroMap(SVal Var, CheckerContext &
C)
const;
86 bool hasDivZeroMap(SVal Var,
const CheckerContext &
C)
const;
87 bool isZero(SVal S, CheckerContext &
C)
const;
99 const Expr *E =
nullptr;
101 if (std::optional<PostStmt> P = Succ->
getLocationAs<PostStmt>())
102 if (
const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
104 if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
105 Op == BO_RemAssign) {
119 PathDiagnosticLocation L =
125 return std::make_shared<PathDiagnosticEventPiece>(
126 L,
"Division with compared value made here");
132bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &
C)
const {
133 std::optional<DefinedSVal> DSV = S.
getAs<DefinedSVal>();
138 ConstraintManager &CM =
C.getConstraintManager();
139 return !CM.
assume(
C.getState(), *DSV,
true);
142void TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &
C)
const {
149 State->add<DivZeroMap>(ZeroState(SR,
C.getBlockID(),
C.getStackFrame()));
150 C.addTransition(State);
153bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
154 const CheckerContext &
C)
const {
159 ZeroState ZS(SR,
C.getBlockID(),
C.getStackFrame());
160 return C.getState()->contains<DivZeroMap>(ZS);
163void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &
C)
const {
164 if (ExplodedNode *N =
C.generateErrorNode(
C.getState())) {
165 auto R = std::make_unique<PathSensitiveBugReport>(
167 "Value being compared against zero has already been used "
171 R->addVisitor(std::make_unique<DivisionBRVisitor>(Val.
getAsSymbol(),
173 C.emitReport(std::move(R));
177void TestAfterDivZeroChecker::checkEndFunction(
const ReturnStmt *,
178 CheckerContext &
C)
const {
181 DivZeroMapTy DivZeroes = State->get<DivZeroMap>();
182 if (DivZeroes.isEmpty())
185 DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>();
186 for (
const ZeroState &ZS : DivZeroes) {
187 if (ZS.getStackFrameContext() ==
C.getStackFrame())
188 DivZeroes = F.remove(DivZeroes, ZS);
190 C.addTransition(State->set<DivZeroMap>(DivZeroes));
193void TestAfterDivZeroChecker::checkPreStmt(
const BinaryOperator *B,
194 CheckerContext &
C)
const {
196 if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
197 Op == BO_RemAssign) {
198 SVal S =
C.getSVal(B->
getRHS());
205void TestAfterDivZeroChecker::checkBranchCondition(
const Stmt *
Condition,
206 CheckerContext &
C)
const {
207 if (
const BinaryOperator *B = dyn_cast<BinaryOperator>(
Condition)) {
209 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->
getRHS());
212 IntLiteral = dyn_cast<IntegerLiteral>(B->
getLHS());
216 if (!IntLiteral || IntLiteral->
getValue() != 0)
220 if (hasDivZeroMap(Val,
C))
223 }
else if (
const UnaryOperator *U = dyn_cast<UnaryOperator>(
Condition)) {
224 if (U->getOpcode() == UO_LNot) {
226 if (
const ImplicitCastExpr *I =
227 dyn_cast<ImplicitCastExpr>(U->getSubExpr()))
228 Val =
C.getSVal(I->getSubExpr());
230 if (hasDivZeroMap(Val,
C))
233 Val =
C.getSVal(U->getSubExpr());
234 if (hasDivZeroMap(Val,
C))
238 }
else if (
const ImplicitCastExpr *IE =
240 SVal Val =
C.getSVal(IE->getSubExpr());
242 if (hasDivZeroMap(Val,
C))
247 if (hasDivZeroMap(Val,
C))
253void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) {
257bool ento::shouldRegisterTestAfterDivZeroChecker(
const CheckerManager &mgr) {
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
llvm::APInt getValue() const
static bool isComparisonOp(Opcode Opc)
BinaryOperatorKind Opcode
bool isValid() const
Return true if this is a valid SourceLocation object.
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond, bool Assumption)
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
const StackFrameContext * getStackFrame() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
std::optional< T > getLocationAs() const &
FullSourceLoc asLocation() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
The JSON file list parser is used to communicate input to InstallAPI.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.