14#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
15#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
22#include "llvm/ADT/BitVector.h"
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/DenseSet.h"
25#include "llvm/ADT/STLExtras.h"
28typedef llvm::ImmutableSet<
29 std::pair<clang::ento::SymbolRef, const llvm::SMTExpr *>>
37 using ConstraintEntry = std::pair<SymbolRef, const llvm::SMTExpr *>;
38 mutable llvm::SMTSolverRef Solver = llvm::CreateZ3Solver();
44 Solver->setBoolParam(
"model",
true);
45 Solver->setUnsignedParam(
"timeout", 15000 );
54 bool Assumption)
override {
60 std::optional<llvm::SMTExprRef> Exp =
72 Assumption ? Exp.value() : Solver->mkNot(Exp.value()));
76 const llvm::APSInt &From,
77 const llvm::APSInt &To,
78 bool InRange)
override {
80 std::optional<llvm::SMTExprRef>
Expr =
88 bool Assumption)
override {
102 std::optional<llvm::SMTExprRef> VarExp =
133 if (
const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
149 std::optional<bool> isSat = Solver->check();
150 if (!isSat || !*isSat)
154 if (!Solver->getInterpretation(Exp,
Value))
161 : Solver->mkBitvector(
Value,
Value.getBitWidth()),
164 Solver->addConstraint(NotExp);
166 std::optional<bool> isNotSat = Solver->check();
167 if (!isNotSat || *isNotSat)
174 if (
const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
181 const llvm::APSInt *
Value;
187 if (
const auto *USE = dyn_cast<UnarySymExpr>(Sym)) {
188 const llvm::APSInt *
Value;
191 std::optional<APSIntPtr> Res = BVF.
evalAPSInt(USE->getOpcode(), *
Value);
192 return Res ? Res.value().get() :
nullptr;
195 if (
const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
196 const llvm::APSInt *LHS, *RHS;
197 if (
const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
199 RHS = SIE->getRHS().get();
200 }
else if (
const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
201 LHS = ISE->getLHS().get();
203 }
else if (
const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
206 RHS = LHS ?
getSymVal(State, SSM->getRHS()) :
nullptr;
208 llvm_unreachable(
"Unsupported binary expression to get symbol value!");
214 llvm::APSInt ConvertedLHS, ConvertedRHS;
219 Solver, Ctx, ConvertedLHS, LTy, ConvertedRHS, RTy);
220 std::optional<APSIntPtr> Res =
221 BVF.
evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS);
222 return Res ? Res.value().get() :
nullptr;
225 llvm_unreachable(
"Unsupported expression to get symbol value!");
231 ConstraintSMTType::Factory &CZFactory = State->get_context<ConstraintSMT>();
233 llvm::DenseMap<SymbolRef, SmallVector<size_t>> ConstraintsBySym;
234 llvm::DenseSet<SymbolRef> TraversedSymbols;
236 llvm::BitVector RetainedConstraints(Constraints.size());
238 for (
auto [Idx, Entry] : llvm::enumerate(Constraints)) {
239 for (
auto Symbol : Entry.first->symbols()) {
240 if (SymReaper.
isLive(Symbol) && TraversedSymbols.insert(Symbol).second)
242 ConstraintsBySym[Symbol].push_back(Idx);
248 for (
auto Idx : ConstraintsBySym[Item]) {
249 if (RetainedConstraints.test(Idx))
252 RetainedConstraints.set(Idx);
254 for (
auto Symbol : Constraints[Idx].first->symbols()) {
255 if (TraversedSymbols.insert(Symbol).second)
261 for (
auto [Idx, Entry] : llvm::enumerate(Constraints)) {
262 if (!RetainedConstraints.test(Idx))
263 CZ = CZFactory.remove(CZ, Entry);
266 return State->set<ConstraintSMT>(CZ);
270 unsigned int Space = 0,
bool IsDot =
false)
const override {
273 Indent(Out, Space, IsDot) <<
"\"constraints\": ";
274 if (Constraints.isEmpty()) {
275 Out <<
"null," << NL;
281 for (ConstraintSMTType::iterator I = Constraints.begin();
282 I != Constraints.end(); ++I) {
284 <<
"{ \"symbol\": \"" << I->first <<
"\", \"range\": \"";
285 I->second->print(Out);
288 if (std::next(I) != Constraints.end())
294 Indent(Out, Space, IsDot) <<
"],";
299 return S1->get<ConstraintSMT>() == S2->get<ConstraintSMT>();
309 const SymExpr *Sym = SymVal->getSymbol();
323 return Solver->isFPSupported();
330 if (
const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
333 if (
const auto *USE = dyn_cast<UnarySymExpr>(Sym))
336 if (
const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
337 if (
const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE))
340 if (
const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE))
343 if (
const SymSymExpr *SSE = dyn_cast<SymSymExpr>(BSE))
348 llvm_unreachable(
"Unsupported expression to reason about!");
351#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
353 LLVM_DUMP_METHOD
void dump()
const { Solver->dump(); }
359 const llvm::SMTExprRef &Exp) {
361 if (
checkModel(State, Sym, Exp).isConstrainedTrue())
362 return State->add<ConstraintSMT>(std::make_pair(Sym, Exp));
371 auto CZ = State->get<ConstraintSMT>();
372 auto I = CZ.begin(), IE = CZ.end();
376 llvm::SMTExprRef Constraint = I++->second;
378 Constraint = Solver->mkAnd(Constraint, I++->second);
381 Solver->addConstraint(Constraint);
387 const llvm::SMTExprRef &Exp)
const {
389 State->add<ConstraintSMT>(std::make_pair(Sym, Exp));
391 llvm::FoldingSetNodeID ID;
392 NewState->get<ConstraintSMT>().Profile(ID);
394 unsigned hash = ID.ComputeHash();
395 auto I =
Cached.find(hash);
402 std::optional<bool> res = Solver->check();
408 mutable llvm::DenseMap<unsigned, ConditionTruthVal>
Cached;
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
llvm::ImmutableSet< std::pair< clang::ento::SymbolRef, const llvm::SMTExpr * > > ConstraintSMTType
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const TargetInfo & getTargetInfo() const
This represents one expression.
A (possibly-)qualified type.
Exposes information about the current target.
const llvm::fltSemantics & getLongDoubleFormat() const
bool isBooleanType() const
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
bool isComplexType() const
isComplexType() does not include complex integers (a GCC extension).
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
bool isComplexIntegerType() const
bool isRealFloatingType() const
Floating point categories.
LLVM_ATTRIBUTE_RETURNS_NONNULL const APSInt * get() const
ASTContext & getContext() const
std::optional< APSIntPtr > evalAPSInt(UnaryOperator::Opcode Op, const llvm::APSInt &V1)
APSIntPtr Convert(const llvm::APSInt &To, const llvm::APSInt &From)
Convert - Create a new persistent APSInt with the same value as 'From' but with the bitwidth and sign...
Represents a symbolic expression involving a binary operator.
bool isConstrainedFalse() const
Return true if the constraint is perfectly constrained to 'false'.
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
SMTConstraintManager(clang::ento::ExprEngine *EE, clang::ento::SValBuilder &SB)
virtual void addStateConstraints(ProgramStateRef State) const
Given a program state, construct the logical conjunction and add it to the solver.
bool canReasonAbout(SVal X) const override
canReasonAbout - Not all ConstraintManagers can accurately reason about all SVal values.
ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, bool InRange) override
Given a symbolic expression within the range [From, To], assume that it is true/false and generate th...
LLVM_DUMP_METHOD void dump() const
Dumps SMT formula.
ConditionTruthVal checkModel(ProgramStateRef State, SymbolRef Sym, const llvm::SMTExprRef &Exp) const
const llvm::APSInt * getSymVal(ProgramStateRef State, SymbolRef Sym) const override
If a symbol is perfectly constrained to a constant, attempt to return the concrete value.
ProgramStateRef removeDeadBindings(ProgramStateRef State, SymbolReaper &SymReaper) override
Scan all symbols referenced by the constraints.
ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override
Returns whether or not a symbol is known to be null ("true"), known to be non-null ("false"),...
ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym, bool Assumption) override
Given a symbolic expression that can be reasoned about, assume that it is true/false and generate the...
llvm::DenseMap< unsigned, ConditionTruthVal > Cached
virtual ~SMTConstraintManager()=default
virtual ProgramStateRef assumeExpr(ProgramStateRef State, SymbolRef Sym, const llvm::SMTExprRef &Exp)
void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL="\n", unsigned int Space=0, bool IsDot=false) const override
ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym, bool Assumption) override
Given a symbolic expression that cannot be reasoned about, assume that it is zero/nonzero and add it ...
bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const override
static std::optional< llvm::SMTExprRef > getRangeExpr(llvm::SMTSolverRef &Solver, ASTContext &Ctx, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, bool InRange)
static llvm::SMTExprRef getZeroExpr(llvm::SMTSolverRef &Solver, ASTContext &Ctx, const llvm::SMTExprRef &Exp, QualType Ty, bool Assumption)
static void doIntTypeConversion(llvm::SMTSolverRef &Solver, ASTContext &Ctx, T &LHS, QualType <y, T &RHS, QualType &RTy)
static std::optional< llvm::SMTExprRef > getExpr(llvm::SMTSolverRef &Solver, ASTContext &Ctx, SymbolRef Sym, QualType &RetTy, bool *hasComparison=nullptr)
static llvm::SMTExprRef fromData(llvm::SMTSolverRef &Solver, ASTContext &Ctx, const SymbolData *Sym)
Construct an SMTSolverRef from a SymbolData.
static llvm::SMTExprRef fromBinOp(llvm::SMTSolverRef &Solver, const llvm::SMTExprRef &LHS, const BinaryOperator::Opcode Op, const llvm::SMTExprRef &RHS, bool isSigned)
Construct an SMTSolverRef from a binary operator.
static std::pair< llvm::APSInt, QualType > fixAPSInt(ASTContext &Ctx, const llvm::APSInt &Int)
static uint64_t getSMTBitWidth(ASTContext &Ctx, QualType Ty)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SValBuilder & getSValBuilder() const
BasicValueFactory & getBasicVals() const
SimpleConstraintManager(ExprEngine *exprengine, SValBuilder &SB)
virtual QualType getType() const =0
Represents a cast expression.
A symbol representing data which can be stored in a memory location (region).
A class responsible for cleaning up unused symbols.
bool isLive(SymbolRef sym)
Represents symbolic expression that isn't a location.
Defines the clang::TargetInfo interface.
BinarySymExprImpl< APSIntPtr, const SymExpr *, SymExpr::Kind::IntSymExprKind > IntSymExpr
Represents a symbolic expression like 3 - 'x'.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
BinarySymExprImpl< const SymExpr *, const SymExpr *, SymExpr::Kind::SymSymExprKind > SymSymExpr
Represents a symbolic expression like 'x' + 'y'.
BinarySymExprImpl< const SymExpr *, APSIntPtr, SymExpr::Kind::SymIntExprKind > SymIntExpr
Represents a symbolic expression like 'x' + 3.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
raw_ostream & Indent(raw_ostream &Out, const unsigned int Space, bool IsDot)