[analyzer] Remove all uses of ConstraintManager::canResonAbout() from

ExprEngine.

Teach SimpleConstraintManager::assumeSymRel() to propagate constraints
to symbolic expressions.

+ One extra warning (real bug) is now generated due to enhanced
assumeSymRel().

llvm-svn: 145832
This commit is contained in:
Anna Zaks 2011-12-05 18:58:25 +00:00
parent 51090d5f7f
commit a636fbe73f
6 changed files with 55 additions and 57 deletions

View File

@ -276,6 +276,7 @@ namespace nonloc {
enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
// TODO: Change to contain symbol data.
class SymbolVal : public NonLoc { class SymbolVal : public NonLoc {
public: public:
SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}

View File

@ -121,8 +121,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
SVal LHSVal; SVal LHSVal;
if (Result.isUnknown() || if (Result.isUnknown()) {
!getConstraintManager().canReasonAbout(Result)) {
unsigned Count = currentBuilderContext->getCurrentBlockCount(); unsigned Count = currentBuilderContext->getCurrentBlockCount();
@ -358,8 +357,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
// Recover some path-sensitivity if a scalar value evaluated to // Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal. // UnknownVal.
if ((InitVal.isUnknown() || if ((InitVal.isUnknown()) &&
!getConstraintManager().canReasonAbout(InitVal)) &&
!VD->getType()->isReferenceType() && !VD->getType()->isReferenceType() &&
!Pred->getState()->isTainted(InitVal)) { !Pred->getState()->isTainted(InitVal)) {
InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
@ -726,7 +724,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
SVal Result = evalBinOp(state, Op, V2, RHS, U->getType()); SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
// Conjure a new symbol if necessary to recover precision. // Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){ if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal = DefinedOrUnknownSVal SymVal =
svalBuilder.getConjuredSymbolVal(NULL, Ex, svalBuilder.getConjuredSymbolVal(NULL, Ex,
currentBuilderContext->getCurrentBlockCount()); currentBuilderContext->getCurrentBlockCount());

View File

@ -550,9 +550,8 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
return true; return true;
isVisited = 1; isVisited = 1;
if (const SymbolData *sData = dyn_cast<SymbolData>(sym)) if (!visitor.VisitSymbol(sym))
if (!visitor.VisitSymbol(sData)) return false;
return false;
switch (sym->getKind()) { switch (sym->getKind()) {
case SymExpr::RegionValueKind: case SymExpr::RegionValueKind:

View File

@ -212,6 +212,40 @@ const ProgramState *SimpleConstraintManager::assumeAux(const ProgramState *state
} // end switch } // end switch
} }
static llvm::APSInt computeAdjustment(const SymExpr *LHS,
SymbolRef &Sym) {
llvm::APSInt DefaultAdjustment;
DefaultAdjustment = 0;
// First check if the LHS is a simple symbol reference.
if (isa<SymbolData>(LHS))
return DefaultAdjustment;
// Next, see if it's a "($sym+constant1)" expression.
const SymIntExpr *SE = dyn_cast<SymIntExpr>(LHS);
// We cannot simplify "($sym1+$sym2)".
if (!SE)
return DefaultAdjustment;
// Get the constant out of the expression "($sym+constant1)" or
// "<expr>+constant1".
Sym = SE->getLHS();
switch (SE->getOpcode()) {
case BO_Add:
return SE->getRHS();
break;
case BO_Sub:
return -SE->getRHS();
break;
default:
// We cannot simplify non-additive operators.
return DefaultAdjustment;
}
return DefaultAdjustment;
}
const ProgramState *SimpleConstraintManager::assumeSymRel(const ProgramState *state, const ProgramState *SimpleConstraintManager::assumeSymRel(const ProgramState *state,
const SymExpr *LHS, const SymExpr *LHS,
BinaryOperator::Opcode op, BinaryOperator::Opcode op,
@ -219,48 +253,15 @@ const ProgramState *SimpleConstraintManager::assumeSymRel(const ProgramState *st
assert(BinaryOperator::isComparisonOp(op) && assert(BinaryOperator::isComparisonOp(op) &&
"Non-comparison ops should be rewritten as comparisons to zero."); "Non-comparison ops should be rewritten as comparisons to zero.");
// We only handle simple comparisons of the form "$sym == constant" // We only handle simple comparisons of the form "$sym == constant"
// or "($sym+constant1) == constant2". // or "($sym+constant1) == constant2".
// The adjustment is "constant1" in the above expression. It's used to // The adjustment is "constant1" in the above expression. It's used to
// "slide" the solution range around for modular arithmetic. For example, // "slide" the solution range around for modular arithmetic. For example,
// x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
// in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
// the subclasses of SimpleConstraintManager to handle the adjustment. // the subclasses of SimpleConstraintManager to handle the adjustment.
llvm::APSInt Adjustment; SymbolRef Sym = LHS;
llvm::APSInt Adjustment = computeAdjustment(LHS, Sym);
// First check if the LHS is a simple symbol reference.
SymbolRef Sym = dyn_cast<SymbolData>(LHS);
if (Sym) {
Adjustment = 0;
} else {
// Next, see if it's a "($sym+constant1)" expression.
const SymIntExpr *SE = dyn_cast<SymIntExpr>(LHS);
// We don't handle "($sym1+$sym2)".
// Give up and assume the constraint is feasible.
if (!SE)
return state;
// We don't handle "(<expr>+constant1)".
// Give up and assume the constraint is feasible.
Sym = dyn_cast<SymbolData>(SE->getLHS());
if (!Sym)
return state;
// Get the constant out of the expression "($sym+constant1)".
switch (SE->getOpcode()) {
case BO_Add:
Adjustment = SE->getRHS();
break;
case BO_Sub:
Adjustment = -SE->getRHS();
break;
default:
// We don't handle non-additive operators.
// Give up and assume the constraint is feasible.
return state;
}
}
// FIXME: This next section is a hack. It silently converts the integers to // FIXME: This next section is a hack. It silently converts the integers to
// be of the same type as the symbol, which is not always correct. Really the // be of the same type as the symbol, which is not always correct. Really the

View File

@ -260,9 +260,10 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
// Wrap the LHS up in a NonLoc again and let evalCastFromNonLoc do the // Wrap the LHS up in a NonLoc again and let evalCastFromNonLoc do the
// dirty work. // dirty work.
if (isIdempotent) { if (isIdempotent) {
if (SymbolRef LHSSym = dyn_cast<SymbolData>(LHS)) if (isa<SymbolData>(LHS))
return evalCastFromNonLoc(nonloc::SymbolVal(LHSSym), resultTy); return evalCastFromNonLoc(nonloc::SymbolVal(LHS), resultTy);
return evalCastFromNonLoc(nonloc::SymExprVal(LHS), resultTy); else
return evalCastFromNonLoc(nonloc::SymExprVal(LHS), resultTy);
} }
// If we reach this point, the expression cannot be simplified. // If we reach this point, the expression cannot be simplified.

View File

@ -128,13 +128,11 @@ void test2_multi_ok(int x) {
buf[0][0] = 1; // no-warning buf[0][0] = 1; // no-warning
} }
// *** FIXME *** // Testing if solver handles (symbol * constant) < constant
// We don't get a warning here yet because our symbolic constraint solving
// doesn't handle: (symbol * constant) < constant
void test3(int x) { void test3(int x) {
int buf[100]; int buf[100];
if (x < 0) if (x < 0)
buf[x] = 1; buf[x] = 1; // expected-warning {{Out of bound memory access (accessed memory precedes memory block)}}
} }
// *** FIXME *** // *** FIXME ***