Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h @@ -21,6 +21,7 @@ namespace clang { namespace ento { +template class SMTConstraintManager : public clang::ento::SimpleConstraintManager { SMTSolverRef &Solver; @@ -34,25 +35,191 @@ // Implementation for interface from SimpleConstraintManager. //===------------------------------------------------------------------===// - ProgramStateRef assumeSym(ProgramStateRef state, SymbolRef Sym, - bool Assumption) override; + ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym, + bool Assumption) override { + ASTContext &Ctx = getBasicVals().getContext(); + + QualType RetTy; + bool hasComparison; + + SMTExprRef Exp = Solver->getExpr(Ctx, Sym, &RetTy, &hasComparison); + + // Create zero comparison for implicit boolean cast, with reversed + // assumption + if (!hasComparison && !RetTy->isBooleanType()) + return assumeExpr(State, Sym, + Solver->getZeroExpr(Ctx, Exp, RetTy, !Assumption)); + + return assumeExpr(State, Sym, Assumption ? Exp : Solver->mkNot(Exp)); + } ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, - bool InRange) override; + bool InRange) override { + ASTContext &Ctx = getBasicVals().getContext(); + return assumeExpr(State, Sym, + Solver->getRangeExpr(Ctx, Sym, From, To, InRange)); + } ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym, - bool Assumption) override; + bool Assumption) override { + // Skip anything that is unsupported + return State; + } //===------------------------------------------------------------------===// // Implementation for interface from ConstraintManager. //===------------------------------------------------------------------===// - ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override; + ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override { + ASTContext &Ctx = getBasicVals().getContext(); + + QualType RetTy; + // The expression may be casted, so we cannot call getZ3DataExpr() directly + SMTExprRef VarExp = Solver->getExpr(Ctx, Sym, &RetTy); + SMTExprRef Exp = + Solver->getZeroExpr(Ctx, VarExp, RetTy, /*Assumption=*/true); + + // Negate the constraint + SMTExprRef NotExp = + Solver->getZeroExpr(Ctx, VarExp, RetTy, /*Assumption=*/false); + + Solver->reset(); + addStateConstraints(State); + + Solver->push(); + Solver->addConstraint(Exp); + ConditionTruthVal isSat = Solver->check(); + + Solver->pop(); + Solver->addConstraint(NotExp); + ConditionTruthVal isNotSat = Solver->check(); + + // Zero is the only possible solution + if (isSat.isConstrainedTrue() && isNotSat.isConstrainedFalse()) + return true; + + // Zero is not a solution + if (isSat.isConstrainedFalse() && isNotSat.isConstrainedTrue()) + return false; + + // Zero may be a solution + return ConditionTruthVal(); + } const llvm::APSInt *getSymVal(ProgramStateRef State, - SymbolRef Sym) const override; + SymbolRef Sym) const override { + BasicValueFactory &BVF = getBasicVals(); + ASTContext &Ctx = BVF.getContext(); + + if (const SymbolData *SD = dyn_cast(Sym)) { + QualType Ty = Sym->getType(); + assert(!Ty->isRealFloatingType()); + llvm::APSInt Value(Ctx.getTypeSize(Ty), + !Ty->isSignedIntegerOrEnumerationType()); + + SMTExprRef Exp = + Solver->fromData(SD->getSymbolID(), Ty, Ctx.getTypeSize(Ty)); + + Solver->reset(); + addStateConstraints(State); + + // Constraints are unsatisfiable + ConditionTruthVal isSat = Solver->check(); + if (!isSat.isConstrainedTrue()) + return nullptr; + + // Model does not assign interpretation + if (!Solver->getInterpretation(Exp, Value)) + return nullptr; + + // A value has been obtained, check if it is the only value + SMTExprRef NotExp = Solver->fromBinOp( + Exp, BO_NE, + Ty->isBooleanType() ? Solver->fromBoolean(Value.getBoolValue()) + : Solver->fromAPSInt(Value), + false); + + Solver->addConstraint(NotExp); + + ConditionTruthVal isNotSat = Solver->check(); + if (isNotSat.isConstrainedTrue()) + return nullptr; + + // This is the only solution, store it + return &BVF.getValue(Value); + } + + if (const SymbolCast *SC = dyn_cast(Sym)) { + SymbolRef CastSym = SC->getOperand(); + QualType CastTy = SC->getType(); + // Skip the void type + if (CastTy->isVoidType()) + return nullptr; + + const llvm::APSInt *Value; + if (!(Value = getSymVal(State, CastSym))) + return nullptr; + return &BVF.Convert(SC->getType(), *Value); + } + + if (const BinarySymExpr *BSE = dyn_cast(Sym)) { + const llvm::APSInt *LHS, *RHS; + if (const SymIntExpr *SIE = dyn_cast(BSE)) { + LHS = getSymVal(State, SIE->getLHS()); + RHS = &SIE->getRHS(); + } else if (const IntSymExpr *ISE = dyn_cast(BSE)) { + LHS = &ISE->getLHS(); + RHS = getSymVal(State, ISE->getRHS()); + } else if (const SymSymExpr *SSM = dyn_cast(BSE)) { + // Early termination to avoid expensive call + LHS = getSymVal(State, SSM->getLHS()); + RHS = LHS ? getSymVal(State, SSM->getRHS()) : nullptr; + } else { + llvm_unreachable("Unsupported binary expression to get symbol value!"); + } + + if (!LHS || !RHS) + return nullptr; + + llvm::APSInt ConvertedLHS, ConvertedRHS; + QualType LTy, RTy; + std::tie(ConvertedLHS, LTy) = Solver->fixAPSInt(Ctx, *LHS); + std::tie(ConvertedRHS, RTy) = Solver->fixAPSInt(Ctx, *RHS); + Solver->doIntTypeConversion( + Ctx, ConvertedLHS, LTy, ConvertedRHS, RTy); + return BVF.evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS); + } + + llvm_unreachable("Unsupported expression to get symbol value!"); + } + + ProgramStateRef removeDeadBindings(ProgramStateRef State, + SymbolReaper &SymReaper) override { + auto CZ = State->get(); + auto &CZFactory = State->get_context(); + + for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) { + if (SymReaper.maybeDead(I->first)) + CZ = CZFactory.remove(CZ, *I); + } + + return State->set(CZ); + } + + void print(ProgramStateRef St, raw_ostream &OS, const char *nl, + const char *sep) override { + + auto CZ = St->get(); + + OS << nl << sep << "Constraints:"; + for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) { + OS << nl << ' ' << I->first << " : "; + I->second.print(OS); + } + OS << nl; + } /// Dumps SMT formula LLVM_DUMP_METHOD void dump() const { Solver->dump(); } @@ -60,15 +227,44 @@ protected: // Check whether a new model is satisfiable, and update the program state. virtual ProgramStateRef assumeExpr(ProgramStateRef State, SymbolRef Sym, - const SMTExprRef &Exp) = 0; + const SMTExprRef &Exp) { + // Check the model, avoid simplifying AST to save time + if (checkModel(State, Exp).isConstrainedTrue()) + return State->add( + std::make_pair(Sym, static_cast(*Exp))); + + return nullptr; + } /// Given a program state, construct the logical conjunction and add it to /// the solver - virtual void addStateConstraints(ProgramStateRef State) const = 0; + virtual void addStateConstraints(ProgramStateRef State) const { + // TODO: Don't add all the constraints, only the relevant ones + auto CZ = State->get(); + auto I = CZ.begin(), IE = CZ.end(); + + // Construct the logical AND of all the constraints + if (I != IE) { + std::vector ASTs; + + SMTExprRef Constraint = Solver->newExprRef(I++->second); + while (I != IE) { + Constraint = Solver->mkAnd(Constraint, Solver->newExprRef(I++->second)); + } + + Solver->addConstraint(Constraint); + } + } // Generate and check a Z3 model, using the given constraint. ConditionTruthVal checkModel(ProgramStateRef State, - const SMTExprRef &Exp) const; + const SMTExprRef &Exp) const { + Solver->reset(); + Solver->addConstraint(Exp); + addStateConstraints(State); + return Solver->check(); + } + }; // end class SMTConstraintManager } // namespace ento Index: cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt +++ cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -49,7 +49,6 @@ SVals.cpp SimpleConstraintManager.cpp SimpleSValBuilder.cpp - SMTConstraintManager.cpp Store.cpp SubEngine.cpp SymbolManager.cpp Index: cfe/trunk/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp @@ -1,181 +0,0 @@ -//== SMTConstraintManager.cpp -----------------------------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" - -using namespace clang; -using namespace ento; - -ProgramStateRef SMTConstraintManager::assumeSym(ProgramStateRef State, - SymbolRef Sym, - bool Assumption) { - ASTContext &Ctx = getBasicVals().getContext(); - - QualType RetTy; - bool hasComparison; - - SMTExprRef Exp = Solver->getExpr(Ctx, Sym, &RetTy, &hasComparison); - - // Create zero comparison for implicit boolean cast, with reversed assumption - if (!hasComparison && !RetTy->isBooleanType()) - return assumeExpr(State, Sym, - Solver->getZeroExpr(Ctx, Exp, RetTy, !Assumption)); - - return assumeExpr(State, Sym, Assumption ? Exp : Solver->mkNot(Exp)); -} - -ProgramStateRef SMTConstraintManager::assumeSymInclusiveRange( - ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, - const llvm::APSInt &To, bool InRange) { - ASTContext &Ctx = getBasicVals().getContext(); - return assumeExpr(State, Sym, - Solver->getRangeExpr(Ctx, Sym, From, To, InRange)); -} - -ProgramStateRef -SMTConstraintManager::assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym, - bool Assumption) { - // Skip anything that is unsupported - return State; -} - -ConditionTruthVal SMTConstraintManager::checkNull(ProgramStateRef State, - SymbolRef Sym) { - ASTContext &Ctx = getBasicVals().getContext(); - - QualType RetTy; - // The expression may be casted, so we cannot call getZ3DataExpr() directly - SMTExprRef VarExp = Solver->getExpr(Ctx, Sym, &RetTy); - SMTExprRef Exp = Solver->getZeroExpr(Ctx, VarExp, RetTy, /*Assumption=*/true); - - // Negate the constraint - SMTExprRef NotExp = - Solver->getZeroExpr(Ctx, VarExp, RetTy, /*Assumption=*/false); - - Solver->reset(); - addStateConstraints(State); - - Solver->push(); - Solver->addConstraint(Exp); - ConditionTruthVal isSat = Solver->check(); - - Solver->pop(); - Solver->addConstraint(NotExp); - ConditionTruthVal isNotSat = Solver->check(); - - // Zero is the only possible solution - if (isSat.isConstrainedTrue() && isNotSat.isConstrainedFalse()) - return true; - - // Zero is not a solution - if (isSat.isConstrainedFalse() && isNotSat.isConstrainedTrue()) - return false; - - // Zero may be a solution - return ConditionTruthVal(); -} - -const llvm::APSInt *SMTConstraintManager::getSymVal(ProgramStateRef State, - SymbolRef Sym) const { - BasicValueFactory &BVF = getBasicVals(); - ASTContext &Ctx = BVF.getContext(); - - if (const SymbolData *SD = dyn_cast(Sym)) { - QualType Ty = Sym->getType(); - assert(!Ty->isRealFloatingType()); - llvm::APSInt Value(Ctx.getTypeSize(Ty), - !Ty->isSignedIntegerOrEnumerationType()); - - SMTExprRef Exp = - Solver->fromData(SD->getSymbolID(), Ty, Ctx.getTypeSize(Ty)); - - Solver->reset(); - addStateConstraints(State); - - // Constraints are unsatisfiable - ConditionTruthVal isSat = Solver->check(); - if (!isSat.isConstrainedTrue()) - return nullptr; - - // Model does not assign interpretation - if (!Solver->getInterpretation(Exp, Value)) - return nullptr; - - // A value has been obtained, check if it is the only value - SMTExprRef NotExp = Solver->fromBinOp( - Exp, BO_NE, - Ty->isBooleanType() ? Solver->fromBoolean(Value.getBoolValue()) - : Solver->fromAPSInt(Value), - false); - - Solver->addConstraint(NotExp); - - ConditionTruthVal isNotSat = Solver->check(); - if (isNotSat.isConstrainedTrue()) - return nullptr; - - // This is the only solution, store it - return &BVF.getValue(Value); - } - - if (const SymbolCast *SC = dyn_cast(Sym)) { - SymbolRef CastSym = SC->getOperand(); - QualType CastTy = SC->getType(); - // Skip the void type - if (CastTy->isVoidType()) - return nullptr; - - const llvm::APSInt *Value; - if (!(Value = getSymVal(State, CastSym))) - return nullptr; - return &BVF.Convert(SC->getType(), *Value); - } - - if (const BinarySymExpr *BSE = dyn_cast(Sym)) { - const llvm::APSInt *LHS, *RHS; - if (const SymIntExpr *SIE = dyn_cast(BSE)) { - LHS = getSymVal(State, SIE->getLHS()); - RHS = &SIE->getRHS(); - } else if (const IntSymExpr *ISE = dyn_cast(BSE)) { - LHS = &ISE->getLHS(); - RHS = getSymVal(State, ISE->getRHS()); - } else if (const SymSymExpr *SSM = dyn_cast(BSE)) { - // Early termination to avoid expensive call - LHS = getSymVal(State, SSM->getLHS()); - RHS = LHS ? getSymVal(State, SSM->getRHS()) : nullptr; - } else { - llvm_unreachable("Unsupported binary expression to get symbol value!"); - } - - if (!LHS || !RHS) - return nullptr; - - llvm::APSInt ConvertedLHS, ConvertedRHS; - QualType LTy, RTy; - std::tie(ConvertedLHS, LTy) = Solver->fixAPSInt(Ctx, *LHS); - std::tie(ConvertedRHS, RTy) = Solver->fixAPSInt(Ctx, *RHS); - Solver->doIntTypeConversion( - Ctx, ConvertedLHS, LTy, ConvertedRHS, RTy); - return BVF.evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS); - } - - llvm_unreachable("Unsupported expression to get symbol value!"); -} - -ConditionTruthVal -SMTConstraintManager::checkModel(ProgramStateRef State, - const SMTExprRef &Exp) const { - Solver->reset(); - Solver->addConstraint(Exp); - addStateConstraints(State); - return Solver->check(); -} Index: cfe/trunk/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp @@ -904,31 +904,13 @@ } }; // end class Z3Solver -class Z3ConstraintManager : public SMTConstraintManager { +class Z3ConstraintManager : public SMTConstraintManager { SMTSolverRef Solver = CreateZ3Solver(); public: Z3ConstraintManager(SubEngine *SE, SValBuilder &SB) : SMTConstraintManager(SE, SB, Solver) {} - void addStateConstraints(ProgramStateRef State) const override { - // TODO: Don't add all the constraints, only the relevant ones - ConstraintZ3Ty CZ = State->get(); - ConstraintZ3Ty::iterator I = CZ.begin(), IE = CZ.end(); - - // Construct the logical AND of all the constraints - if (I != IE) { - std::vector ASTs; - - SMTExprRef Constraint = Solver->newExprRef(I++->second); - while (I != IE) { - Constraint = Solver->mkAnd(Constraint, Solver->newExprRef(I++->second)); - } - - Solver->addConstraint(Constraint); - } - } - bool canReasonAbout(SVal X) const override { const TargetInfo &TI = getBasicVals().getContext().getTargetInfo(); @@ -971,45 +953,6 @@ llvm_unreachable("Unsupported expression to reason about!"); } - - ProgramStateRef removeDeadBindings(ProgramStateRef State, - SymbolReaper &SymReaper) override { - ConstraintZ3Ty CZ = State->get(); - ConstraintZ3Ty::Factory &CZFactory = State->get_context(); - - for (ConstraintZ3Ty::iterator I = CZ.begin(), E = CZ.end(); I != E; ++I) { - if (SymReaper.maybeDead(I->first)) - CZ = CZFactory.remove(CZ, *I); - } - - return State->set(CZ); - } - - ProgramStateRef assumeExpr(ProgramStateRef State, SymbolRef Sym, - const SMTExprRef &Exp) override { - // Check the model, avoid simplifying AST to save time - if (checkModel(State, Exp).isConstrainedTrue()) - return State->add(std::make_pair(Sym, toZ3Expr(*Exp))); - - return nullptr; - } - - //==------------------------------------------------------------------------==/ - // Pretty-printing. - //==------------------------------------------------------------------------==/ - - void print(ProgramStateRef St, raw_ostream &OS, const char *nl, - const char *sep) override { - - ConstraintZ3Ty CZ = St->get(); - - OS << nl << sep << "Constraints:"; - for (ConstraintZ3Ty::iterator I = CZ.begin(), E = CZ.end(); I != E; ++I) { - OS << nl << ' ' << I->first << " : "; - I->second.print(OS); - } - OS << nl; - } }; // end class Z3ConstraintManager } // end anonymous namespace