clang  3.9.0
SimpleConstraintManager.cpp
Go to the documentation of this file.
1 //== SimpleConstraintManager.cpp --------------------------------*- C++ -*--==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines SimpleConstraintManager, a class that holds code shared
11 // between BasicConstraintManager and RangeConstraintManager.
12 //
13 //===----------------------------------------------------------------------===//
14 
19 
20 namespace clang {
21 
22 namespace ento {
23 
25 
28  if (SymVal && SymVal->isExpression()) {
29  const SymExpr *SE = SymVal->getSymbol();
30 
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.
34  case BO_And:
35  case BO_Or:
36  case BO_Xor:
37  return false;
38  // We don't reason yet about these arithmetic constraints on
39  // symbolic values.
40  case BO_Mul:
41  case BO_Div:
42  case BO_Rem:
43  case BO_Shl:
44  case BO_Shr:
45  return false;
46  // All other cases.
47  default:
48  return true;
49  }
50  }
51 
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()));
57  return true;
58  }
59  }
60  }
61 
62  return false;
63  }
64 
65  return true;
66 }
67 
69  DefinedSVal Cond,
70  bool Assumption) {
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();
74  QualType T;
75  const MemRegion *MR = LV->getAsRegion();
76  if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR))
77  T = TR->getLocationType();
78  else
79  T = SVB.getContext().VoidPtrTy;
80 
81  Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>();
82  }
83 
84  return assume(state, Cond.castAs<NonLoc>(), Assumption);
85 }
86 
88  NonLoc cond,
89  bool assumption) {
90  state = assumeAux(state, cond, assumption);
91  if (NotifyAssumeClients && SU)
92  return SU->processAssume(state, cond, assumption);
93  return state;
94 }
95 
96 
99  SymbolRef Sym, bool Assumption) {
101  QualType T = Sym->getType();
102 
103  // None of the constraint solvers currently support non-integer types.
104  if (!T->isIntegralOrEnumerationType())
105  return State;
106 
107  const llvm::APSInt &zero = BVF.getValue(0, T);
108  if (Assumption)
109  return assumeSymNE(State, Sym, zero, zero);
110  else
111  return assumeSymEQ(State, Sym, zero, zero);
112 }
113 
115  NonLoc Cond,
116  bool Assumption) {
117 
118  // We cannot reason about SymSymExprs, and can only reason about some
119  // SymIntExprs.
120  if (!canReasonAbout(Cond)) {
121  // Just add the constraint to the expression without trying to simplify.
122  SymbolRef sym = Cond.getAsSymExpr();
123  return assumeAuxForSymbol(state, sym, Assumption);
124  }
125 
126  switch (Cond.getSubKind()) {
127  default:
128  llvm_unreachable("'Assume' not implemented for this NonLoc");
129 
130  case nonloc::SymbolValKind: {
132  SymbolRef sym = SV.getSymbol();
133  assert(sym);
134 
135  // Handle SymbolData.
136  if (!SV.isExpression()) {
137  return assumeAuxForSymbol(state, sym, Assumption);
138 
139  // Handle symbolic expression.
140  } else if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym)) {
141  // We can only simplify expressions whose RHS is an integer.
142 
143  BinaryOperator::Opcode op = SE->getOpcode();
145  if (!Assumption)
147 
148  return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
149  }
150 
151  } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(sym)) {
152  // Translate "a != b" to "(b - a) != 0".
153  // We invert the order of the operands as a heuristic for how loop
154  // conditions are usually written ("begin != end") as compared to length
155  // calculations ("end - begin"). The more correct thing to do would be to
156  // canonicalize "a - b" and "b - a", which would allow us to treat
157  // "a != b" and "b != a" the same.
158  SymbolManager &SymMgr = getSymbolManager();
159  BinaryOperator::Opcode Op = SSE->getOpcode();
160  assert(BinaryOperator::isComparisonOp(Op));
161 
162  // For now, we only support comparing pointers.
163  assert(Loc::isLocType(SSE->getLHS()->getType()));
164  assert(Loc::isLocType(SSE->getRHS()->getType()));
165  QualType DiffTy = SymMgr.getContext().getPointerDiffType();
166  SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
167  SSE->getLHS(), DiffTy);
168 
169  const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
171  if (!Assumption)
173  return assumeSymRel(state, Subtraction, Op, Zero);
174  }
175 
176  // If we get here, there's nothing else we can do but treat the symbol as
177  // opaque.
178  return assumeAuxForSymbol(state, sym, Assumption);
179  }
180 
181  case nonloc::ConcreteIntKind: {
182  bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0;
183  bool isFeasible = b ? Assumption : !Assumption;
184  return isFeasible ? state : nullptr;
185  }
186 
187  case nonloc::LocAsIntegerKind:
188  return assume(state, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
189  Assumption);
190  } // end switch
191 }
192 
194  ProgramStateRef State, NonLoc Value, const llvm::APSInt &From,
195  const llvm::APSInt &To, bool InRange) {
196 
197  assert(From.isUnsigned() == To.isUnsigned() &&
198  From.getBitWidth() == To.getBitWidth() &&
199  "Values should have same types!");
200 
201  if (!canReasonAbout(Value)) {
202  // Just add the constraint to the expression without trying to simplify.
203  SymbolRef Sym = Value.getAsSymExpr();
204  assert(Sym);
205  return assumeSymWithinInclusiveRange(State, Sym, From, To, InRange);
206  }
207 
208  switch (Value.getSubKind()) {
209  default:
210  llvm_unreachable("'assumeWithinInclusiveRange' is not implemented"
211  "for this NonLoc");
212 
213  case nonloc::LocAsIntegerKind:
214  case nonloc::SymbolValKind: {
215  if (SymbolRef Sym = Value.getAsSymbol())
216  return assumeSymWithinInclusiveRange(State, Sym, From, To, InRange);
217  return State;
218  } // end switch
219 
220  case nonloc::ConcreteIntKind: {
221  const llvm::APSInt &IntVal = Value.castAs<nonloc::ConcreteInt>().getValue();
222  bool IsInRange = IntVal >= From && IntVal <= To;
223  bool isFeasible = (IsInRange == InRange);
224  return isFeasible ? State : nullptr;
225  }
226  } // end switch
227 }
228 
229 static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment) {
230  // Is it a "($sym+constant1)" expression?
231  if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
232  BinaryOperator::Opcode Op = SE->getOpcode();
233  if (Op == BO_Add || Op == BO_Sub) {
234  Sym = SE->getLHS();
235  Adjustment = APSIntType(Adjustment).convert(SE->getRHS());
236 
237  // Don't forget to negate the adjustment if it's being subtracted.
238  // This should happen /after/ promotion, in case the value being
239  // subtracted is, say, CHAR_MIN, and the promoted type is 'int'.
240  if (Op == BO_Sub)
241  Adjustment = -Adjustment;
242  }
243  }
244 }
245 
247  const SymExpr *LHS,
249  const llvm::APSInt& Int) {
250  assert(BinaryOperator::isComparisonOp(op) &&
251  "Non-comparison ops should be rewritten as comparisons to zero.");
252 
253  // Get the type used for calculating wraparound.
255  APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType());
256 
257  // We only handle simple comparisons of the form "$sym == constant"
258  // or "($sym+constant1) == constant2".
259  // The adjustment is "constant1" in the above expression. It's used to
260  // "slide" the solution range around for modular arithmetic. For example,
261  // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
262  // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
263  // the subclasses of SimpleConstraintManager to handle the adjustment.
264  SymbolRef Sym = LHS;
265  llvm::APSInt Adjustment = WraparoundType.getZeroValue();
266  computeAdjustment(Sym, Adjustment);
267 
268  // Convert the right-hand side integer as necessary.
269  APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
270  llvm::APSInt ConvertedInt = ComparisonType.convert(Int);
271 
272  // Prefer unsigned comparisons.
273  if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
274  ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
275  Adjustment.setIsSigned(false);
276 
277  switch (op) {
278  default:
279  llvm_unreachable("invalid operation not caught by assertion above");
280 
281  case BO_EQ:
282  return assumeSymEQ(state, Sym, ConvertedInt, Adjustment);
283 
284  case BO_NE:
285  return assumeSymNE(state, Sym, ConvertedInt, Adjustment);
286 
287  case BO_GT:
288  return assumeSymGT(state, Sym, ConvertedInt, Adjustment);
289 
290  case BO_GE:
291  return assumeSymGE(state, Sym, ConvertedInt, Adjustment);
292 
293  case BO_LT:
294  return assumeSymLT(state, Sym, ConvertedInt, Adjustment);
295 
296  case BO_LE:
297  return assumeSymLE(state, Sym, ConvertedInt, Adjustment);
298  } // end switch
299 }
300 
303  SymbolRef Sym,
304  const llvm::APSInt &From,
305  const llvm::APSInt &To,
306  bool InRange) {
307  // Get the type used for calculating wraparound.
309  APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType());
310 
311  llvm::APSInt Adjustment = WraparoundType.getZeroValue();
312  SymbolRef AdjustedSym = Sym;
313  computeAdjustment(AdjustedSym, Adjustment);
314 
315  // Convert the right-hand side integer as necessary.
316  APSIntType ComparisonType = std::max(WraparoundType, APSIntType(From));
317  llvm::APSInt ConvertedFrom = ComparisonType.convert(From);
318  llvm::APSInt ConvertedTo = ComparisonType.convert(To);
319 
320  // Prefer unsigned comparisons.
321  if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
322  ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
323  Adjustment.setIsSigned(false);
324 
325  if (InRange)
326  return assumeSymbolWithinInclusiveRange(State, AdjustedSym, ConvertedFrom,
327  ConvertedTo, Adjustment);
328  return assumeSymbolOutOfInclusiveRange(State, AdjustedSym, ConvertedFrom,
329  ConvertedTo, Adjustment);
330 }
331 
332 } // end of namespace ento
333 
334 } // end of namespace clang
const SymExpr * getAsSymExpr() const
Definition: SVals.cpp:128
CanQualType VoidPtrTy
Definition: ASTContext.h:908
A (possibly-)qualified type.
Definition: Type.h:598
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:79
virtual ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment)=0
SVal evalCast(SVal val, QualType castTy, QualType originalType)
Value representing integer constant.
Definition: SVals.h:341
virtual ProgramStateRef assumeSymbolOutOfInclusiveRange(ProgramStateRef state, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, const llvm::APSInt &Adjustment)=0
Symbolic value.
Definition: SymExpr.h:29
bool isComparisonOp() const
Definition: Expr.h:2990
static Opcode reverseComparisonOp(Opcode Opc)
Definition: Expr.h:3005
virtual ProgramStateRef assumeSymGT(ProgramStateRef state, SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment)=0
LineState State
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
bool NotifyAssumeClients
A flag to indicate that clients should be notified of assumptions.
static bool isLocType(QualType T)
Definition: SVals.h:291
BinaryOperatorKind
ProgramStateRef assumeWithinInclusiveRange(ProgramStateRef State, NonLoc Value, const llvm::APSInt &From, const llvm::APSInt &To, bool InRange) override
uint32_t getBitWidth() const
Definition: APSIntType.h:31
A record of the "type" of an APSInt, used for conversions.
Definition: APSIntType.h:20
virtual ProgramStateRef assumeSymGE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment)=0
Represents a symbolic expression like 'x' + 3.
virtual ProgramStateRef assumeSymEQ(ProgramStateRef state, SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment)=0
llvm::APSInt getZeroValue() const LLVM_READONLY
Returns an all-zero value for this type.
Definition: APSIntType.h:56
virtual QualType getType() const =0
static Opcode negateComparisonOp(Opcode Opc)
Definition: Expr.h:2992
bool isUnsigned() const
Definition: APSIntType.h:32
virtual ProgramStateRef assumeSymbolWithinInclusiveRange(ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, const llvm::APSInt &Adjustment)=0
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:86
virtual ProgramStateRef assumeSymLE(ProgramStateRef state, SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment)=0
virtual ProgramStateRef processAssume(ProgramStateRef state, SVal cond, bool assumption)=0
Called by ConstraintManager.
static SVal getValue(SVal val, SValBuilder &svalBuilder)
ProgramStateRef assumeSymRel(ProgramStateRef state, const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt &Int)
const SymSymExpr * getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t)
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:5730
ProgramStateRef assumeAux(ProgramStateRef state, NonLoc Cond, bool Assumption)
ProgramStateRef assumeSymWithinInclusiveRange(ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, bool InRange)
ASTContext & getContext()
Definition: SValBuilder.h:126
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:46
ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond, bool Assumption) override
SymbolRef getSymbol() const
Definition: SVals.h:319
llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY
Convert and return a new APSInt with the given value, but this type's bit width and signedness...
Definition: APSIntType.h:49
unsigned getSubKind() const
Definition: SVals.h:100
ProgramStateRef assumeAuxForSymbol(ProgramStateRef State, SymbolRef Sym, bool Assumption)
bool isExpression() const
Definition: SVals.h:323
Represents symbolic expression.
Definition: SVals.h:315
QualType getPointerDiffType() const
Return the unique type for "ptrdiff_t" (C99 7.17) defined in <stddef.h>.
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Definition: SemaDecl.cpp:12171
static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment)
bool canReasonAbout(SVal X) const override
canReasonAbout - Not all ConstraintManagers can accurately reason about all SVal values.
virtual ProgramStateRef assumeSymLT(ProgramStateRef state, SymbolRef sym, const llvm::APSInt &V, const llvm::APSInt &Adjustment)=0
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition: SVals.cpp:111
APSIntType getAPSIntType(QualType T) const
Returns the type of the APSInt used to store values of the given QualType.
CanQualType BoolTy
Definition: ASTContext.h:894
BasicValueFactory & getBasicVals() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:75
Represents a symbolic expression like 'x' + 'y'.
TypedRegion - An abstract class representing regions that are typed.
Definition: MemRegion.h:472