aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/GRExprEngineInternalChecks.cpp
diff options
context:
space:
mode:
authorZhongxing Xu <xuzhongxing@gmail.com>2009-09-02 13:26:26 +0000
committerZhongxing Xu <xuzhongxing@gmail.com>2009-09-02 13:26:26 +0000
commit6403b57eda05a22273d920ad0bd2991d11eaa7b8 (patch)
treeab637a053e55c1442059e9fba282eae561ff113f /lib/Analysis/GRExprEngineInternalChecks.cpp
parentde18d1264ea01234ca864606a8717272b2c7c5fb (diff)
Refactor the check for bad divide into a checker.
Also fix a checker context bug: the Dst set is not always empty initially. Because in GRExprEngine::CheckerVisit(), *CurrSet is used repeatedly. So we removed the Dst.empty() condition in ~CheckerContext() when deciding whether to do autotransision. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80786 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/GRExprEngineInternalChecks.cpp')
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp78
1 files changed, 68 insertions, 10 deletions
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index 4c6371c44c..28e763376a 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -193,14 +193,10 @@ public:
class VISIBILITY_HIDDEN DivZero : public BuiltinBug {
public:
- DivZero(GRExprEngine* eng)
+ DivZero(GRExprEngine* eng = 0)
: BuiltinBug(eng,"Division-by-zero",
"Division by zero or undefined value.") {}
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.explicit_bad_divides_begin(), Eng.explicit_bad_divides_end());
- }
-
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode* N,
BuiltinBugReport *R) {
@@ -575,7 +571,7 @@ public:
if (stateNull && !stateNotNull) {
// Generate an error node. Check for a null node in case
// we cache out.
- if (ExplodedNode *errorNode = C.generateNode(CE, stateNull, true)) {
+ if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {
// Lazily allocate the BugType object if it hasn't already been
// created. Ownership is transferred to the BugReporter object once
@@ -611,7 +607,7 @@ public:
// If we reach here all of the arguments passed the nonnull check.
// If 'state' has been updated generated a new node.
if (state != originalState)
- C.addTransition(C.generateNode(CE, state));
+ C.addTransition(C.GenerateNode(CE, state));
}
};
} // end anonymous namespace
@@ -639,7 +635,7 @@ void CheckUndefinedArg::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE){
for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
if (C.getState()->getSVal(*I).isUndef()) {
- if (ExplodedNode *ErrorNode = C.generateNode(CE, C.getState(), true)) {
+ if (ExplodedNode *ErrorNode = C.GenerateNode(CE, true)) {
if (!BT)
BT = new BadArg();
// Generate a report for this bug.
@@ -672,7 +668,7 @@ void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
SVal L = C.getState()->getSVal(Callee);
if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
- if (ExplodedNode *N = C.generateNode(CE, C.getState(), true)) {
+ if (ExplodedNode *N = C.GenerateNode(CE, true)) {
if (!BT)
BT = new BadCall();
C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
@@ -680,6 +676,68 @@ void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
}
}
+class VISIBILITY_HIDDEN CheckBadDiv : public CheckerVisitor<CheckBadDiv> {
+ DivZero *BT;
+public:
+ CheckBadDiv() : BT(0) {}
+ ~CheckBadDiv() {}
+
+ const void *getTag() {
+ static int x;
+ return &x;
+ }
+
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+
+void CheckBadDiv::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ BinaryOperator::Opcode Op = B->getOpcode();
+ if (Op != BinaryOperator::Div &&
+ Op != BinaryOperator::Rem &&
+ Op != BinaryOperator::DivAssign &&
+ Op != BinaryOperator::RemAssign)
+ return;
+
+ if (!B->getRHS()->getType()->isIntegerType() ||
+ !B->getRHS()->getType()->isScalarType())
+ return;
+
+ printf("should not check!\n");
+
+ // Check for divide by undefined.
+ SVal Denom = C.getState()->getSVal(B->getRHS());
+
+ if (Denom.isUndef()) {
+ if (ExplodedNode *N = C.GenerateNode(B, true)) {
+ if (!BT)
+ BT = new DivZero();
+
+ C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
+ }
+ return;
+ }
+
+ // Check for divide by zero.
+ ConstraintManager &CM = C.getConstraintManager();
+ const GRState *stateNotZero, *stateZero;
+ llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(),
+ cast<DefinedSVal>(Denom));
+
+ if (stateZero && !stateNotZero) {
+ if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
+ if (!BT)
+ BT = new DivZero();
+
+ C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N));
+ }
+ return;
+ }
+
+ // If we get here, then the denom should not be zero.
+ if (stateNotZero != C.getState())
+ C.addTransition(C.GenerateNode(B, stateNotZero));
+}
}
//===----------------------------------------------------------------------===//
// Check registration.
@@ -694,7 +752,6 @@ void GRExprEngine::RegisterInternalChecks() {
BR.Register(new NullDeref(this));
BR.Register(new UndefinedDeref(this));
BR.Register(new UndefBranch(this));
- BR.Register(new DivZero(this));
BR.Register(new UndefResult(this));
BR.Register(new RetStack(this));
BR.Register(new RetUndef(this));
@@ -713,4 +770,5 @@ void GRExprEngine::RegisterInternalChecks() {
registerCheck(new CheckAttrNonNull());
registerCheck(new CheckUndefinedArg());
registerCheck(new CheckBadCall());
+ registerCheck(new CheckBadDiv());
}