1 //== SimpleConstraintManager.cpp --------------------------------*- C++ -*--==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines SimpleConstraintManager, a class that holds code shared
11 // between BasicConstraintManager and RangeConstraintManager.
13 //===----------------------------------------------------------------------===//
15 #include "SimpleConstraintManager.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
24 SimpleConstraintManager::~SimpleConstraintManager() {}
26 bool SimpleConstraintManager::canReasonAbout(SVal X) const {
27 Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
28 if (SymVal && SymVal->isExpression()) {
29 const SymExpr *SE = SymVal->getSymbol();
31 if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
32 switch (SIE->getOpcode()) {
33 // We don't reason yet about bitwise-constraints on symbolic values.
38 // We don't reason yet about these arithmetic constraints on
52 if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
53 if (BinaryOperator::isComparisonOp(SSE->getOpcode())) {
54 // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc.
55 if (Loc::isLocType(SSE->getLHS()->getType())) {
56 assert(Loc::isLocType(SSE->getRHS()->getType()));
68 ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
71 // If we have a Loc value, cast it to a bool NonLoc first.
72 if (Optional<Loc> LV = Cond.getAs<Loc>()) {
73 SValBuilder &SVB = State->getStateManager().getSValBuilder();
75 const MemRegion *MR = LV->getAsRegion();
76 if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR))
77 T = TR->getLocationType();
79 T = SVB.getContext().VoidPtrTy;
81 Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>();
84 return assume(State, Cond.castAs<NonLoc>(), Assumption);
87 ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
88 NonLoc Cond, bool Assumption) {
89 State = assumeAux(State, Cond, Assumption);
90 if (NotifyAssumeClients && SU)
91 return SU->processAssume(State, Cond, Assumption);
96 SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State,
97 SymbolRef Sym, bool Assumption) {
98 BasicValueFactory &BVF = getBasicVals();
99 QualType T = Sym->getType();
101 // None of the constraint solvers currently support non-integer types.
102 if (!T->isIntegralOrEnumerationType())
105 const llvm::APSInt &zero = BVF.getValue(0, T);
107 return assumeSymNE(State, Sym, zero, zero);
109 return assumeSymEQ(State, Sym, zero, zero);
112 ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
116 // We cannot reason about SymSymExprs, and can only reason about some
118 if (!canReasonAbout(Cond)) {
119 // Just add the constraint to the expression without trying to simplify.
120 SymbolRef Sym = Cond.getAsSymExpr();
121 return assumeAuxForSymbol(State, Sym, Assumption);
124 switch (Cond.getSubKind()) {
126 llvm_unreachable("'Assume' not implemented for this NonLoc");
128 case nonloc::SymbolValKind: {
129 nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>();
130 SymbolRef Sym = SV.getSymbol();
133 // Handle SymbolData.
134 if (!SV.isExpression()) {
135 return assumeAuxForSymbol(State, Sym, Assumption);
137 // Handle symbolic expression.
138 } else if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
139 // We can only simplify expressions whose RHS is an integer.
141 BinaryOperator::Opcode Op = SE->getOpcode();
142 if (BinaryOperator::isComparisonOp(Op)) {
144 Op = BinaryOperator::negateComparisonOp(Op);
146 return assumeSymRel(State, SE->getLHS(), Op, SE->getRHS());
149 } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(Sym)) {
150 // Translate "a != b" to "(b - a) != 0".
151 // We invert the order of the operands as a heuristic for how loop
152 // conditions are usually written ("begin != end") as compared to length
153 // calculations ("end - begin"). The more correct thing to do would be to
154 // canonicalize "a - b" and "b - a", which would allow us to treat
155 // "a != b" and "b != a" the same.
156 SymbolManager &SymMgr = getSymbolManager();
157 BinaryOperator::Opcode Op = SSE->getOpcode();
158 assert(BinaryOperator::isComparisonOp(Op));
160 // For now, we only support comparing pointers.
161 assert(Loc::isLocType(SSE->getLHS()->getType()));
162 assert(Loc::isLocType(SSE->getRHS()->getType()));
163 QualType DiffTy = SymMgr.getContext().getPointerDiffType();
164 SymbolRef Subtraction =
165 SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub, SSE->getLHS(), DiffTy);
167 const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
168 Op = BinaryOperator::reverseComparisonOp(Op);
170 Op = BinaryOperator::negateComparisonOp(Op);
171 return assumeSymRel(State, Subtraction, Op, Zero);
174 // If we get here, there's nothing else we can do but treat the symbol as
176 return assumeAuxForSymbol(State, Sym, Assumption);
179 case nonloc::ConcreteIntKind: {
180 bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0;
181 bool isFeasible = b ? Assumption : !Assumption;
182 return isFeasible ? State : nullptr;
185 case nonloc::PointerToMemberKind: {
186 bool IsNull = !Cond.castAs<nonloc::PointerToMember>().isNullMemberPointer();
187 bool IsFeasible = IsNull ? Assumption : !Assumption;
188 return IsFeasible ? State : nullptr;
191 case nonloc::LocAsIntegerKind:
192 return assume(State, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
197 ProgramStateRef SimpleConstraintManager::assumeInclusiveRange(
198 ProgramStateRef State, NonLoc Value, const llvm::APSInt &From,
199 const llvm::APSInt &To, bool InRange) {
201 assert(From.isUnsigned() == To.isUnsigned() &&
202 From.getBitWidth() == To.getBitWidth() &&
203 "Values should have same types!");
205 if (!canReasonAbout(Value)) {
206 // Just add the constraint to the expression without trying to simplify.
207 SymbolRef Sym = Value.getAsSymExpr();
209 return assumeSymWithinInclusiveRange(State, Sym, From, To, InRange);
212 switch (Value.getSubKind()) {
214 llvm_unreachable("'assumeInclusiveRange' is not implemented"
217 case nonloc::LocAsIntegerKind:
218 case nonloc::SymbolValKind: {
219 if (SymbolRef Sym = Value.getAsSymbol())
220 return assumeSymWithinInclusiveRange(State, Sym, From, To, InRange);
224 case nonloc::ConcreteIntKind: {
225 const llvm::APSInt &IntVal = Value.castAs<nonloc::ConcreteInt>().getValue();
226 bool IsInRange = IntVal >= From && IntVal <= To;
227 bool isFeasible = (IsInRange == InRange);
228 return isFeasible ? State : nullptr;
233 static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment) {
234 // Is it a "($sym+constant1)" expression?
235 if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
236 BinaryOperator::Opcode Op = SE->getOpcode();
237 if (Op == BO_Add || Op == BO_Sub) {
239 Adjustment = APSIntType(Adjustment).convert(SE->getRHS());
241 // Don't forget to negate the adjustment if it's being subtracted.
242 // This should happen /after/ promotion, in case the value being
243 // subtracted is, say, CHAR_MIN, and the promoted type is 'int'.
245 Adjustment = -Adjustment;
250 ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef State,
252 BinaryOperator::Opcode Op,
253 const llvm::APSInt &Int) {
254 assert(BinaryOperator::isComparisonOp(Op) &&
255 "Non-comparison ops should be rewritten as comparisons to zero.");
259 // Simplification: translate an assume of a constraint of the form
260 // "(exp comparison_op expr) != 0" to true into an assume of
261 // "exp comparison_op expr" to true. (And similarly, an assume of the form
262 // "(exp comparison_op expr) == 0" to true into an assume of
263 // "exp comparison_op expr" to false.)
264 if (Int == 0 && (Op == BO_EQ || Op == BO_NE)) {
265 if (const BinarySymExpr *SE = dyn_cast<BinarySymExpr>(Sym))
266 if (BinaryOperator::isComparisonOp(SE->getOpcode()))
267 return assume(State, nonloc::SymbolVal(Sym), (Op == BO_NE ? true : false));
270 // Get the type used for calculating wraparound.
271 BasicValueFactory &BVF = getBasicVals();
272 APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType());
274 // We only handle simple comparisons of the form "$sym == constant"
275 // or "($sym+constant1) == constant2".
276 // The adjustment is "constant1" in the above expression. It's used to
277 // "slide" the solution range around for modular arithmetic. For example,
278 // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
279 // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
280 // the subclasses of SimpleConstraintManager to handle the adjustment.
281 llvm::APSInt Adjustment = WraparoundType.getZeroValue();
282 computeAdjustment(Sym, Adjustment);
284 // Convert the right-hand side integer as necessary.
285 APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
286 llvm::APSInt ConvertedInt = ComparisonType.convert(Int);
288 // Prefer unsigned comparisons.
289 if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
290 ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
291 Adjustment.setIsSigned(false);
295 llvm_unreachable("invalid operation not caught by assertion above");
298 return assumeSymEQ(State, Sym, ConvertedInt, Adjustment);
301 return assumeSymNE(State, Sym, ConvertedInt, Adjustment);
304 return assumeSymGT(State, Sym, ConvertedInt, Adjustment);
307 return assumeSymGE(State, Sym, ConvertedInt, Adjustment);
310 return assumeSymLT(State, Sym, ConvertedInt, Adjustment);
313 return assumeSymLE(State, Sym, ConvertedInt, Adjustment);
317 ProgramStateRef SimpleConstraintManager::assumeSymWithinInclusiveRange(
318 ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
319 const llvm::APSInt &To, bool InRange) {
320 // Get the type used for calculating wraparound.
321 BasicValueFactory &BVF = getBasicVals();
322 APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType());
324 llvm::APSInt Adjustment = WraparoundType.getZeroValue();
325 SymbolRef AdjustedSym = Sym;
326 computeAdjustment(AdjustedSym, Adjustment);
328 // Convert the right-hand side integer as necessary.
329 APSIntType ComparisonType = std::max(WraparoundType, APSIntType(From));
330 llvm::APSInt ConvertedFrom = ComparisonType.convert(From);
331 llvm::APSInt ConvertedTo = ComparisonType.convert(To);
333 // Prefer unsigned comparisons.
334 if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
335 ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
336 Adjustment.setIsSigned(false);
339 return assumeSymbolWithinInclusiveRange(State, AdjustedSym, ConvertedFrom,
340 ConvertedTo, Adjustment);
341 return assumeSymbolOutOfInclusiveRange(State, AdjustedSym, ConvertedFrom,
342 ConvertedTo, Adjustment);
345 } // end of namespace ento
347 } // end of namespace clang