clang 20.0.0git
SMTConstraintManager.h
Go to the documentation of this file.
1//== SMTConstraintManager.h -------------------------------------*- C++ -*--==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a SMT generic API, which will be the base class for
10// every SMT solver specific class.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
15#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
16
22#include <optional>
23
24typedef llvm::ImmutableSet<
25 std::pair<clang::ento::SymbolRef, const llvm::SMTExpr *>>
28
29namespace clang {
30namespace ento {
31
33 mutable llvm::SMTSolverRef Solver = llvm::CreateZ3Solver();
34
35public:
38 : SimpleConstraintManager(EE, SB) {
39 Solver->setBoolParam("model", true); // Enable model finding
40 Solver->setUnsignedParam("timeout", 15000 /*milliseconds*/);
41 }
42 virtual ~SMTConstraintManager() = default;
43
44 //===------------------------------------------------------------------===//
45 // Implementation for interface from SimpleConstraintManager.
46 //===------------------------------------------------------------------===//
47
49 bool Assumption) override {
51
52 QualType RetTy;
53 bool hasComparison;
54
55 llvm::SMTExprRef Exp =
56 SMTConv::getExpr(Solver, Ctx, Sym, &RetTy, &hasComparison);
57
58 // Create zero comparison for implicit boolean cast, with reversed
59 // assumption
60 if (!hasComparison && !RetTy->isBooleanType())
61 return assumeExpr(
62 State, Sym,
63 SMTConv::getZeroExpr(Solver, Ctx, Exp, RetTy, !Assumption));
64
65 return assumeExpr(State, Sym, Assumption ? Exp : Solver->mkNot(Exp));
66 }
67
69 const llvm::APSInt &From,
70 const llvm::APSInt &To,
71 bool InRange) override {
73 return assumeExpr(
74 State, Sym, SMTConv::getRangeExpr(Solver, Ctx, Sym, From, To, InRange));
75 }
76
78 bool Assumption) override {
79 // Skip anything that is unsupported
80 return State;
81 }
82
83 //===------------------------------------------------------------------===//
84 // Implementation for interface from ConstraintManager.
85 //===------------------------------------------------------------------===//
86
89
90 QualType RetTy;
91 // The expression may be casted, so we cannot call getZ3DataExpr() directly
92 llvm::SMTExprRef VarExp = SMTConv::getExpr(Solver, Ctx, Sym, &RetTy);
93 llvm::SMTExprRef Exp =
94 SMTConv::getZeroExpr(Solver, Ctx, VarExp, RetTy, /*Assumption=*/true);
95
96 // Negate the constraint
97 llvm::SMTExprRef NotExp =
98 SMTConv::getZeroExpr(Solver, Ctx, VarExp, RetTy, /*Assumption=*/false);
99
100 ConditionTruthVal isSat = checkModel(State, Sym, Exp);
101 ConditionTruthVal isNotSat = checkModel(State, Sym, NotExp);
102
103 // Zero is the only possible solution
104 if (isSat.isConstrainedTrue() && isNotSat.isConstrainedFalse())
105 return true;
106
107 // Zero is not a solution
108 if (isSat.isConstrainedFalse() && isNotSat.isConstrainedTrue())
109 return false;
110
111 // Zero may be a solution
112 return ConditionTruthVal();
113 }
114
115 const llvm::APSInt *getSymVal(ProgramStateRef State,
116 SymbolRef Sym) const override {
118 ASTContext &Ctx = BVF.getContext();
119
120 if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
121 QualType Ty = Sym->getType();
122 assert(!Ty->isRealFloatingType());
123 llvm::APSInt Value(Ctx.getTypeSize(Ty),
125
126 // TODO: this should call checkModel so we can use the cache, however,
127 // this method tries to get the interpretation (the actual value) from
128 // the solver, which is currently not cached.
129
130 llvm::SMTExprRef Exp = SMTConv::fromData(Solver, Ctx, SD);
131
132 Solver->reset();
133 addStateConstraints(State);
134
135 // Constraints are unsatisfiable
136 std::optional<bool> isSat = Solver->check();
137 if (!isSat || !*isSat)
138 return nullptr;
139
140 // Model does not assign interpretation
141 if (!Solver->getInterpretation(Exp, Value))
142 return nullptr;
143
144 // A value has been obtained, check if it is the only value
145 llvm::SMTExprRef NotExp = SMTConv::fromBinOp(
146 Solver, Exp, BO_NE,
147 Ty->isBooleanType() ? Solver->mkBoolean(Value.getBoolValue())
148 : Solver->mkBitvector(Value, Value.getBitWidth()),
149 /*isSigned=*/false);
150
151 Solver->addConstraint(NotExp);
152
153 std::optional<bool> isNotSat = Solver->check();
154 if (!isNotSat || *isNotSat)
155 return nullptr;
156
157 // This is the only solution, store it
158 return BVF.getValue(Value).get();
159 }
160
161 if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
162 SymbolRef CastSym = SC->getOperand();
163 QualType CastTy = SC->getType();
164 // Skip the void type
165 if (CastTy->isVoidType())
166 return nullptr;
167
168 const llvm::APSInt *Value;
169 if (!(Value = getSymVal(State, CastSym)))
170 return nullptr;
171 return BVF.Convert(SC->getType(), *Value).get();
172 }
173
174 if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
175 const llvm::APSInt *LHS, *RHS;
176 if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
177 LHS = getSymVal(State, SIE->getLHS());
178 RHS = SIE->getRHS().get();
179 } else if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
180 LHS = ISE->getLHS().get();
181 RHS = getSymVal(State, ISE->getRHS());
182 } else if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
183 // Early termination to avoid expensive call
184 LHS = getSymVal(State, SSM->getLHS());
185 RHS = LHS ?