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 
17 #include "clang/Basic/JsonSupport.h"
18 #include "clang/Basic/TargetInfo.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
21 
22 typedef llvm::ImmutableSet<
23     std::pair<clang::ento::SymbolRef, const llvm::SMTExpr *>>
24     ConstraintSMTType;
25 REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintSMT, ConstraintSMTType)
26 
27 namespace clang {
28 namespace ento {
29 
30 class SMTConstraintManager : public clang::ento::SimpleConstraintManager {
31   mutable llvm::SMTSolverRef Solver = llvm::CreateZ3Solver();
32 
33 public:
34   SMTConstraintManager(clang::ento::ExprEngine *EE,
35                        clang::ento::SValBuilder &SB)
36       : SimpleConstraintManager(EE, SB) {}
37   virtual ~SMTConstraintManager() = default;
38 
39   //===------------------------------------------------------------------===//
40   // Implementation for interface from SimpleConstraintManager.
41   //===------------------------------------------------------------------===//
42 
43   ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
44                             bool Assumption) override {
45     ASTContext &Ctx = getBasicVals().getContext();
46 
47     QualType RetTy;
48     bool hasComparison;
49 
50     llvm::SMTExprRef Exp =
51         SMTConv::getExpr(Solver, Ctx, Sym, &RetTy, &hasComparison);
52 
53     // Create zero comparison for implicit boolean cast, with reversed
54     // assumption
55     if (!hasComparison && !RetTy->isBooleanType())
56       return assumeExpr(
57           State, Sym,
58           SMTConv::getZeroExpr(Solver, Ctx, Exp, RetTy, !Assumption));
59 
60     return assumeExpr(State, Sym, Assumption ? Exp : Solver->mkNot(Exp));
61   }
62 
63   ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym,
64                                           const llvm::APSInt &From,
65                                           const llvm::APSInt &To,
66                                           bool InRange) override {
67     ASTContext &Ctx = getBasicVals().getContext();
68     return assumeExpr(
69         State, Sym, SMTConv::getRangeExpr(Solver, Ctx, Sym, From, To, InRange));
70   }
71 
72   ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym,
73                                        bool Assumption) override {
74     // Skip anything that is unsupported
75     return State;
76   }
77 
78   //===------------------------------------------------------------------===//
79   // Implementation for interface from ConstraintManager.
80   //===------------------------------------------------------------------===//
81 
82   ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override {
83     ASTContext &Ctx = getBasicVals().getContext();
84 
85     QualType RetTy;
86     // The expression may be casted, so we cannot call getZ3DataExpr() directly
87     llvm::SMTExprRef VarExp = SMTConv::getExpr(Solver, Ctx, Sym, &RetTy);
88     llvm::SMTExprRef Exp =
89         SMTConv::getZeroExpr(Solver, Ctx, VarExp, RetTy, /*Assumption=*/true);
90 
91     // Negate the constraint
92     llvm::SMTExprRef NotExp =
93         SMTConv::getZeroExpr(Solver, Ctx, VarExp, RetTy, /*Assumption=*/false);
94 
95     ConditionTruthVal isSat = checkModel(State, Sym, Exp);
96     ConditionTruthVal isNotSat = checkModel(State, Sym, NotExp);
97 
98     // Zero is the only possible solution
99     if (isSat.isConstrainedTrue() && isNotSat.isConstrainedFalse())
100       return true;
101 
102     // Zero is not a solution
103     if (isSat.isConstrainedFalse() && isNotSat.isConstrainedTrue())
104       return false;
105 
106     // Zero may be a solution
107     return ConditionTruthVal();
108   }
109 
110   const llvm::APSInt *getSymVal(ProgramStateRef State,
111                                 SymbolRef Sym) const override {
112     BasicValueFactory &BVF = getBasicVals();
113     ASTContext &Ctx = BVF.getContext();
114 
115     if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
116       QualType Ty = Sym->getType();
117       assert(!Ty->isRealFloatingType());
118       llvm::APSInt Value(Ctx.getTypeSize(Ty),
119                          !Ty->isSignedIntegerOrEnumerationType());
120 
121       // TODO: this should call checkModel so we can use the cache, however,
122       // this method tries to get the interpretation (the actual value) from
123       // the solver, which is currently not cached.
124 
125       llvm::SMTExprRef Exp = SMTConv::fromData(Solver, Ctx, SD);
126 
127       Solver->reset();
128       addStateConstraints(State);
129 
130       // Constraints are unsatisfiable
131       Optional<bool> isSat = Solver->check();
132       if (!isSat.hasValue() || !isSat.getValue())
133         return nullptr;
134 
135       // Model does not assign interpretation
136       if (!Solver->getInterpretation(Exp, Value))
137         return nullptr;
138 
139       // A value has been obtained, check if it is the only value
140       llvm::SMTExprRef NotExp = SMTConv::fromBinOp(
141           Solver, Exp, BO_NE,
142           Ty->isBooleanType() ? Solver->mkBoolean(Value.getBoolValue())
143                               : Solver->mkBitvector(Value, Value.getBitWidth()),
144           /*isSigned=*/false);
145 
146       Solver->addConstraint(NotExp);
147 
148       Optional<bool> isNotSat = Solver->check();
149       if (!isSat.hasValue() || isNotSat.getValue())
150         return nullptr;
151 
152       // This is the only solution, store it
153       return &BVF.getValue(Value);
154     }
155 
156     if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
157       SymbolRef CastSym = SC->getOperand();
158       QualType CastTy = SC->getType();
159       // Skip the void type
160       if (CastTy->isVoidType())
161         return nullptr;
162 
163       const llvm::APSInt *Value;
164       if (!(Value = getSymVal(State, CastSym)))
165         return nullptr;
166       return &BVF.Convert(SC->getType(), *Value);
167     }
168 
169     if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
170       const llvm::APSInt *LHS, *RHS;
171       if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
172         LHS = getSymVal(State, SIE->getLHS());
173         RHS = &SIE->getRHS();
174       } else if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
175         LHS = &ISE->getLHS();
176         RHS = getSymVal(State, ISE->getRHS());
177       } else if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
178         // Early termination to avoid expensive call
179         LHS = getSymVal(State, SSM->getLHS());
180         RHS = LHS ? getSymVal(State, SSM->getRHS()) : nullptr;
181       } else {
182         llvm_unreachable("Unsupported binary expression to get symbol value!");
183       }
184 
185       if (!LHS || !RHS)
186         return nullptr;
187 
188       llvm::APSInt ConvertedLHS, ConvertedRHS;
189       QualType LTy, RTy;
190       std::tie(ConvertedLHS, LTy) = SMTConv::fixAPSInt(Ctx, *LHS);
191       std::tie(ConvertedRHS, RTy) = SMTConv::fixAPSInt(Ctx, *RHS);
192       SMTConv::doIntTypeConversion<llvm::APSInt, &SMTConv::castAPSInt>(
193           Solver, Ctx, ConvertedLHS, LTy, ConvertedRHS, RTy);
194       return BVF.evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS);
195     }
196 
197     llvm_unreachable("Unsupported expression to get symbol value!");
198   }
199 
200   ProgramStateRef removeDeadBindings(ProgramStateRef State,
201                                      SymbolReaper &SymReaper) override {
202     auto CZ = State->get<ConstraintSMT>();
203     auto &CZFactory = State->get_context<ConstraintSMT>();
204 
205     for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) {
206       if (SymReaper.isDead(I->first))
207         CZ = CZFactory.remove(CZ, *I);
208     }
209 
210     return State->set<ConstraintSMT>(CZ);
211   }
212 
213   void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n",
214                  unsigned int Space = 0, bool IsDot = false) const override {
215     ConstraintSMTType Constraints = State->get<ConstraintSMT>();
216 
217     Indent(Out, Space, IsDot) << "\"constraints\": ";
218     if (Constraints.isEmpty()) {
219       Out << "null," << NL;
220       return;
221     }
222 
223     ++Space;
224     Out << '[' << NL;
225     for (ConstraintSMTType::iterator I = Constraints.begin();
226          I != Constraints.end(); ++I) {
227       Indent(Out, Space, IsDot)
228           << "{ \"symbol\": \"" << I->first << "\", \"range\": \"";
229       I->second->print(Out);
230       Out << "\" }";
231 
232       if (std::next(I) != Constraints.end())
233         Out << ',';
234       Out << NL;
235     }
236 
237     --Space;
238     Indent(Out, Space, IsDot) << "],";
239   }
240 
241   bool haveEqualConstraints(ProgramStateRef S1,
242                             ProgramStateRef S2) const override {
243     return S1->get<ConstraintSMT>() == S2->get<ConstraintSMT>();
244   }
245 
246   bool canReasonAbout(SVal X) const override {
247     const TargetInfo &TI = getBasicVals().getContext().getTargetInfo();
248 
249     Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
250     if (!SymVal)
251       return true;
252 
253     const SymExpr *Sym = SymVal->getSymbol();
254     QualType Ty = Sym->getType();
255 
256     // Complex types are not modeled
257     if (Ty->isComplexType() || Ty->isComplexIntegerType())
258       return false;
259 
260     // Non-IEEE 754 floating-point types are not modeled
261     if ((Ty->isSpecificBuiltinType(BuiltinType::LongDouble) &&
262          (&TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended() ||
263           &TI.getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble())))
264       return false;
265 
266     if (Ty->isRealFloatingType())
267       return Solver->isFPSupported();
268 
269     if (isa<SymbolData>(Sym))
270       return true;
271 
272     SValBuilder &SVB = getSValBuilder();
273 
274     if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
275       return canReasonAbout(SVB.makeSymbolVal(SC->getOperand()));
276 
277     if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
278       if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE))
279         return canReasonAbout(SVB.makeSymbolVal(SIE->getLHS()));
280 
281       if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE))
282         return canReasonAbout(SVB.makeSymbolVal(ISE->getRHS()));
283 
284       if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(BSE))
285         return canReasonAbout(SVB.makeSymbolVal(SSE->getLHS())) &&
286                canReasonAbout(SVB.makeSymbolVal(SSE->getRHS()));
287     }
288 
289     llvm_unreachable("Unsupported expression to reason about!");
290   }
291 
292   /// Dumps SMT formula
293   LLVM_DUMP_METHOD void dump() const { Solver->dump(); }
294 
295 protected:
296   // Check whether a new model is satisfiable, and update the program state.
297   virtual ProgramStateRef assumeExpr(ProgramStateRef State, SymbolRef Sym,
298                                      const llvm::SMTExprRef &Exp) {
299     // Check the model, avoid simplifying AST to save time
300     if (checkModel(State, Sym, Exp).isConstrainedTrue())
301       return State->add<ConstraintSMT>(std::make_pair(Sym, Exp));
302 
303     return nullptr;
304   }
305 
306   /// Given a program state, construct the logical conjunction and add it to
307   /// the solver
308   virtual void addStateConstraints(ProgramStateRef State) const {
309     // TODO: Don't add all the constraints, only the relevant ones
310     auto CZ = State->get<ConstraintSMT>();
311     auto I = CZ.begin(), IE = CZ.end();
312 
313     // Construct the logical AND of all the constraints
314     if (I != IE) {
315       std::vector<llvm::SMTExprRef> ASTs;
316 
317       llvm::SMTExprRef Constraint = I++->second;
318       while (I != IE) {
319         Constraint = Solver->mkAnd(Constraint, I++->second);
320       }
321 
322       Solver->addConstraint(Constraint);
323     }
324   }
325 
326   // Generate and check a Z3 model, using the given constraint.
327   ConditionTruthVal checkModel(ProgramStateRef State, SymbolRef Sym,
328                                const llvm::SMTExprRef &Exp) const {
329     ProgramStateRef NewState =
330         State->add<ConstraintSMT>(std::make_pair(Sym, Exp));
331 
332     llvm::FoldingSetNodeID ID;
333     NewState->get<ConstraintSMT>().Profile(ID);
334 
335     unsigned hash = ID.ComputeHash();
336     auto I = Cached.find(hash);
337     if (I != Cached.end())
338       return I->second;
339 
340     Solver->reset();
341     addStateConstraints(NewState);
342 
343     Optional<bool> res = Solver->check();
344     if (!res.hasValue())
345       Cached[hash] = ConditionTruthVal();
346     else
347       Cached[hash] = ConditionTruthVal(res.getValue());
348 
349     return Cached[hash];
350   }
351 
352   // Cache the result of an SMT query (true, false, unknown). The key is the
353   // hash of the constraints in a state
354   mutable llvm::DenseMap<unsigned, ConditionTruthVal> Cached;
355 }; // end class SMTConstraintManager
356 
357 } // namespace ento
358 } // namespace clang
359 
360 #endif
361