#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 ConstNotEqTy; typedef llvm::ImmutableMap 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(Cond)) return Assume(St, cast(Cond), Assumption, isFeasible); else return Assume(St, cast(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(Cond).getSymbol(), BasicVals.getZeroWithPtrWidth(), isFeasible); else return AssumeSymEQ(St, cast(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(Cond).getBase(), Assumption, isFeasible); case lval::ArrayOffsetKind: return AssumeAux(St, cast(Cond).getBase(), Assumption, isFeasible); case lval::ConcreteIntKind: { bool b = cast(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(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(Cond).getConstraint(), isFeasible); case nonlval::ConcreteIntKind: { bool b = cast(Cond).getValue() != 0; isFeasible = b ? Assumption : !Assumption; return St; } case nonlval::LValAsIntegerKind: return AssumeAux(St, cast(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; }