forked from OSchip/llvm-project
[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:
parent
51090d5f7f
commit
a636fbe73f
|
@ -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) {}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 ***
|
||||||
|
|
Loading…
Reference in New Issue