diff options
Diffstat (limited to 'lib/Analysis/BasicConstraintManager.cpp')
-rw-r--r-- | lib/Analysis/BasicConstraintManager.cpp | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp new file mode 100644 index 0000000000..efe5b93da4 --- /dev/null +++ b/lib/Analysis/BasicConstraintManager.cpp @@ -0,0 +1,298 @@ +#include "clang/Analysis/PathSensitive/ConstraintManager.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +namespace { + +// BasicConstraintManager only tracks equality and inequality constraints of +// constants and integer variables. +class VISIBILITY_HIDDEN BasicConstraintManager : public ConstraintManager { + typedef llvm::ImmutableMap<SymbolID, GRState::IntSetTy> ConstNotEqTy; + typedef llvm::ImmutableMap<SymbolID, const llvm::APSInt*> ConstEqTy; + + GRStateManager& StateMgr; + +public: + BasicConstraintManager(GRStateManager& statemgr) : StateMgr(statemgr) {} + + virtual const GRState* Assume(const GRState* St, RVal Cond, + bool Assumption, bool& isFeasible); + + const GRState* Assume(const GRState* St, LVal Cond, bool Assumption, + bool& isFeasible); + + const GRState* AssumeAux(const GRState* St, LVal Cond,bool Assumption, + bool& isFeasible); + + const GRState* Assume(const GRState* St, NonLVal Cond, bool Assumption, + bool& isFeasible); + + const GRState* AssumeAux(const GRState* St, NonLVal Cond, bool Assumption, + bool& isFeasible); + + const GRState* AssumeSymInt(const GRState* St, bool Assumption, + const SymIntConstraint& C, bool& isFeasible); + + const GRState* AssumeSymNE(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible); + + const GRState* AssumeSymEQ(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible); + + const GRState* AssumeSymLT(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible); + + const GRState* AssumeSymGT(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible); + + const GRState* AssumeSymGE(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible); + + const GRState* AssumeSymLE(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible); + }; + +} // end anonymous namespace + +ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr) +{ + return new BasicConstraintManager(StateMgr); +} + +const GRState* BasicConstraintManager::Assume(const GRState* St, RVal Cond, + bool Assumption, bool& isFeasible) { + if (Cond.isUnknown()) { + isFeasible = true; + return St; + } + + if (isa<NonLVal>(Cond)) + return Assume(St, cast<NonLVal>(Cond), Assumption, isFeasible); + else + return Assume(St, cast<LVal>(Cond), Assumption, isFeasible); +} + +const GRState* BasicConstraintManager::Assume(const GRState* St, LVal Cond, + bool Assumption, bool& isFeasible) { + St = AssumeAux(St, Cond, Assumption, isFeasible); + // TF->EvalAssume(*this, St, Cond, Assumption, isFeasible) + return St; +} + +const GRState* BasicConstraintManager::AssumeAux(const GRState* St, LVal Cond, + bool Assumption, bool& isFeasible) { + BasicValueFactory& BasicVals = StateMgr.getBasicVals(); + + switch (Cond.getSubKind()) { + default: + assert (false && "'Assume' not implemented for this LVal."); + return St; + + case lval::SymbolValKind: + if (Assumption) + return AssumeSymNE(St, cast<lval::SymbolVal>(Cond).getSymbol(), + BasicVals.getZeroWithPtrWidth(), isFeasible); + else + return AssumeSymEQ(St, cast<lval::SymbolVal>(Cond).getSymbol(), + BasicVals.getZeroWithPtrWidth(), isFeasible); + + case lval::DeclValKind: + case lval::FuncValKind: + case lval::GotoLabelKind: + case lval::StringLiteralValKind: + isFeasible = Assumption; + return St; + + case lval::FieldOffsetKind: + return AssumeAux(St, cast<lval::FieldOffset>(Cond).getBase(), + Assumption, isFeasible); + + case lval::ArrayOffsetKind: + return AssumeAux(St, cast<lval::ArrayOffset>(Cond).getBase(), + Assumption, isFeasible); + + case lval::ConcreteIntKind: { + bool b = cast<lval::ConcreteInt>(Cond).getValue() != 0; + isFeasible = b ? Assumption : !Assumption; + return St; + } + } // end switch +} + +const GRState* +BasicConstraintManager::Assume(const GRState* St, NonLVal Cond, bool Assumption, + bool& isFeasible) { + St = AssumeAux(St, Cond, Assumption, isFeasible); + // TF->EvalAssume() does nothing now. + return St; +} + +const GRState* +BasicConstraintManager::AssumeAux(const GRState* St,NonLVal Cond, + bool Assumption, bool& isFeasible) { + BasicValueFactory& BasicVals = StateMgr.getBasicVals(); + SymbolManager& SymMgr = StateMgr.getSymbolManager(); + + switch (Cond.getSubKind()) { + default: + assert(false && "'Assume' not implemented for this NonLVal"); + + case nonlval::SymbolValKind: { + nonlval::SymbolVal& SV = cast<nonlval::SymbolVal>(Cond); + SymbolID sym = SV.getSymbol(); + + if (Assumption) + return AssumeSymNE(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)), + isFeasible); + else + return AssumeSymEQ(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)), + isFeasible); + } + + case nonlval::SymIntConstraintValKind: + return + AssumeSymInt(St, Assumption, + cast<nonlval::SymIntConstraintVal>(Cond).getConstraint(), + isFeasible); + + case nonlval::ConcreteIntKind: { + bool b = cast<nonlval::ConcreteInt>(Cond).getValue() != 0; + isFeasible = b ? Assumption : !Assumption; + return St; + } + + case nonlval::LValAsIntegerKind: + return AssumeAux(St, cast<nonlval::LValAsInteger>(Cond).getLVal(), + Assumption, isFeasible); + } // end switch +} + +const GRState* +BasicConstraintManager::AssumeSymInt(const GRState* St, bool Assumption, + const SymIntConstraint& C, bool& isFeasible) { + + switch (C.getOpcode()) { + default: + // No logic yet for other operators. + isFeasible = true; + return St; + + case BinaryOperator::EQ: + if (Assumption) + return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible); + else + return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible); + + case BinaryOperator::NE: + if (Assumption) + return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible); + else + return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible); + + case BinaryOperator::GE: + if (Assumption) + return AssumeSymGE(St, C.getSymbol(), C.getInt(), isFeasible); + else + return AssumeSymLT(St, C.getSymbol(), C.getInt(), isFeasible); + + case BinaryOperator::LE: + if (Assumption) + return AssumeSymLE(St, C.getSymbol(), C.getInt(), isFeasible); + else + return AssumeSymGT(St, C.getSymbol(), C.getInt(), isFeasible); + } // end switch +} + +const GRState* +BasicConstraintManager::AssumeSymNE(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + // First, determine if sym == X, where X != V. + if (const llvm::APSInt* X = St->getSymVal(sym)) { + isFeasible = (*X != V); + return St; + } + + // Second, determine if sym != V. + if (St->isNotEqual(sym, V)) { + isFeasible = true; + return St; + } + + // If we reach here, sym is not a constant and we don't know if it is != V. + // Make that assumption. + isFeasible = true; + return StateMgr.AddNE(St, sym, V); +} + +const GRState* +BasicConstraintManager::AssumeSymEQ(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + // First, determine if sym == X, where X != V. + if (const llvm::APSInt* X = St->getSymVal(sym)) { + isFeasible = *X == V; + return St; + } + + // Second, determine if sym != V. + if (St->isNotEqual(sym, V)) { + isFeasible = false; + return St; + } + + // If we reach here, sym is not a constant and we don't know if it is == V. + // Make that assumption. + + isFeasible = true; + return StateMgr.AddEQ(St, sym, V); +} + +// These logic will be handled in another ConstraintManager. +const GRState* +BasicConstraintManager::AssumeSymLT(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + + // FIXME: For now have assuming x < y be the same as assuming sym != V; + return AssumeSymNE(St, sym, V, isFeasible); +} + +const GRState* +BasicConstraintManager::AssumeSymGT(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + + // FIXME: For now have assuming x > y be the same as assuming sym != V; + return AssumeSymNE(St, sym, V, isFeasible); +} + +const GRState* +BasicConstraintManager::AssumeSymGE(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + + // FIXME: Primitive logic for now. Only reject a path if the value of + // sym is a constant X and !(X >= V). + + if (const llvm::APSInt* X = St->getSymVal(sym)) { + isFeasible = *X >= V; + return St; + } + + isFeasible = true; + return St; +} + +const GRState* +BasicConstraintManager::AssumeSymLE(const GRState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + + // FIXME: Primitive logic for now. Only reject a path if the value of + // sym is a constant X and !(X <= V). + + if (const llvm::APSInt* X = St->getSymVal(sym)) { + isFeasible = *X <= V; + return St; + } + + isFeasible = true; + return St; +} |