blob: b34fbf65341a905aac921b476c0f4fc93f200373 [file] [log] [blame]
Ted Kremenek45021952009-02-14 17:08:39 +00001//== RangeConstraintManager.cpp - Manage range constraints.------*- 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 RangeConstraintManager, a class that tracks simple
11// equality and inequality constraints on symbolic values of GRState.
12//
13//===----------------------------------------------------------------------===//
14
15#include "SimpleConstraintManager.h"
16#include "clang/Analysis/PathSensitive/GRState.h"
17#include "clang/Analysis/PathSensitive/GRStateTrait.h"
18#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
19#include "clang/Driver/ManagerRegistry.h"
20#include "llvm/Support/Compiler.h"
21#include "llvm/Support/Debug.h"
22#include "llvm/ADT/FoldingSet.h"
23#include "llvm/ADT/ImmutableSet.h"
24#include "llvm/Support/raw_ostream.h"
25
26using namespace clang;
27
Ted Kremenek9beefec2009-02-17 19:28:04 +000028namespace { class VISIBILITY_HIDDEN ConstraintRange {}; }
29static int ConstraintRangeIndex = 0;
Ted Kremenek45021952009-02-14 17:08:39 +000030
Ted Kremenek9beefec2009-02-17 19:28:04 +000031/// A Range represents the closed range [from, to]. The caller must
32/// guarantee that from <= to. Note that Range is immutable, so as not
33/// to subvert RangeSet's immutability.
34class Range : public std::pair<const llvm::APSInt*, const llvm::APSInt*> {
Ted Kremenek45021952009-02-14 17:08:39 +000035public:
36 Range(const llvm::APSInt &from, const llvm::APSInt &to)
Ted Kremenek9beefec2009-02-17 19:28:04 +000037 : std::pair<const llvm::APSInt*, const llvm::APSInt*>(&from, &to) {
Ted Kremenek45021952009-02-14 17:08:39 +000038 assert(from <= to);
39 }
40 bool Includes(const llvm::APSInt &v) const {
Ted Kremenek9beefec2009-02-17 19:28:04 +000041 return *first <= v && v <= *second;
Ted Kremenek45021952009-02-14 17:08:39 +000042 }
43 const llvm::APSInt &From() const {
Ted Kremenek9beefec2009-02-17 19:28:04 +000044 return *first;
Ted Kremenek45021952009-02-14 17:08:39 +000045 }
46 const llvm::APSInt &To() const {
Ted Kremenek9beefec2009-02-17 19:28:04 +000047 return *second;
Ted Kremenek45021952009-02-14 17:08:39 +000048 }
Ted Kremenek9beefec2009-02-17 19:28:04 +000049 const llvm::APSInt *getConcreteValue() const {
50 return &From() == &To() ? &From() : NULL;
Ted Kremenek45021952009-02-14 17:08:39 +000051 }
52
53 void Profile(llvm::FoldingSetNodeID &ID) const {
Ted Kremenek9beefec2009-02-17 19:28:04 +000054 ID.AddPointer(&From());
55 ID.AddPointer(&To());
Ted Kremenek45021952009-02-14 17:08:39 +000056 }
57};
58
Ted Kremenek9beefec2009-02-17 19:28:04 +000059/// RangeSet contains a set of ranges. If the set is empty, then
60/// there the value of a symbol is overly constrained and there are no
61/// possible values for that symbol.
Ted Kremenek45021952009-02-14 17:08:39 +000062class RangeSet {
Ted Kremenek9beefec2009-02-17 19:28:04 +000063 typedef llvm::ImmutableSet<Range> PrimRangeSet;
Ted Kremenek45021952009-02-14 17:08:39 +000064 PrimRangeSet ranges; // no need to make const, since it is an
65 // ImmutableSet - this allows default operator=
Ted Kremenek9beefec2009-02-17 19:28:04 +000066 // to work.
Ted Kremenek45021952009-02-14 17:08:39 +000067public:
Ted Kremenek9beefec2009-02-17 19:28:04 +000068 typedef PrimRangeSet::Factory Factory;
69 typedef PrimRangeSet::iterator iterator;
70
71 RangeSet(PrimRangeSet RS) : ranges(RS) {}
72 RangeSet(Factory& F) : ranges(F.GetEmptySet()) {}
73
74 iterator begin() const { return ranges.begin(); }
75 iterator end() const { return ranges.end(); }
76
77 bool isEmpty() const { return ranges.isEmpty(); }
78
79 /// Construct a new RangeSet representing '{ [from, to] }'.
80 RangeSet(Factory &F, const llvm::APSInt &from, const llvm::APSInt &to)
81 : ranges(F.Add(F.GetEmptySet(), Range(from, to))) {}
82
83 /// Profile - Generates a hash profile of this RangeSet for use
84 /// by FoldingSet.
85 void Profile(llvm::FoldingSetNodeID &ID) const { ranges.Profile(ID); }
86
87 /// getConcreteValue - If a symbol is contrained to equal a specific integer
88 /// constant then this method returns that value. Otherwise, it returns
89 /// NULL.
90 const llvm::APSInt* getConcreteValue() const {
91 return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0;
Ted Kremenek45021952009-02-14 17:08:39 +000092 }
93
Ted Kremenek9beefec2009-02-17 19:28:04 +000094 /// AddEQ - Create a new RangeSet with the additional constraint that the
95 /// value be equal to V.
96 RangeSet AddEQ(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
97 // Search for a range that includes 'V'. If so, return a new RangeSet
98 // representing { [V, V] }.
99 for (PrimRangeSet::iterator i = begin(), e = end(); i!=e; ++i)
100 if (i->Includes(V))
101 return RangeSet(F, V, V);
102
103 return RangeSet(F);
Ted Kremenek45021952009-02-14 17:08:39 +0000104 }
105
Ted Kremenek9beefec2009-02-17 19:28:04 +0000106 /// AddNE - Create a new RangeSet with the additional constraint that the
107 /// value be not be equal to V.
108 RangeSet AddNE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
109 PrimRangeSet newRanges = ranges;
110
111 // FIXME: We can perhaps enhance ImmutableSet to do this search for us
112 // in log(N) time using the sorted property of the internal AVL tree.
113 for (iterator i = begin(), e = end(); i != e; ++i) {
114 if (i->Includes(V)) {
115 // Remove the old range.
116 newRanges = F.Remove(newRanges, *i);
117 // Split the old range into possibly one or two ranges.
118 if (V != i->From())
119 newRanges = F.Add(newRanges, Range(i->From(), BV.Sub1(V)));
120 if (V != i->To())
121 newRanges = F.Add(newRanges, Range(BV.Add1(V), i->To()));
122 // All of the ranges are non-overlapping, so we can stop.
123 break;
Ted Kremenek45021952009-02-14 17:08:39 +0000124 }
125 }
Ted Kremenek9beefec2009-02-17 19:28:04 +0000126
127 return newRanges;
Ted Kremenek45021952009-02-14 17:08:39 +0000128 }
129
Ted Kremenek9beefec2009-02-17 19:28:04 +0000130 /// AddNE - Create a new RangeSet with the additional constraint that the
131 /// value be less than V.
132 RangeSet AddLT(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
133 PrimRangeSet newRanges = F.GetEmptySet();
134
135 for (iterator i = begin(), e = end() ; i != e ; ++i) {
136 if (i->Includes(V) && i->From() < V)
137 newRanges = F.Add(newRanges, Range(i->From(), BV.Sub1(V)));
138 else if (i->To() < V)
139 newRanges = F.Add(newRanges, *i);
140 }
141
142 return newRanges;
Ted Kremenek45021952009-02-14 17:08:39 +0000143 }
144
Ted Kremenek9beefec2009-02-17 19:28:04 +0000145 RangeSet AddLE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
146 PrimRangeSet newRanges = F.GetEmptySet();
Ted Kremenek45021952009-02-14 17:08:39 +0000147
Ted Kremenek9beefec2009-02-17 19:28:04 +0000148 for (iterator i = begin(), e = end(); i != e; ++i) {
149 // Strictly we should test for includes *V + 1, but no harm is
Ted Kremenek45021952009-02-14 17:08:39 +0000150 // done by this formulation
Ted Kremenek9beefec2009-02-17 19:28:04 +0000151 if (i->Includes(V))
152 newRanges = F.Add(newRanges, Range(i->From(), V));
153 else if (i->To() <= V)
154 newRanges = F.Add(newRanges, *i);
Ted Kremenek45021952009-02-14 17:08:39 +0000155 }
Ted Kremenek9beefec2009-02-17 19:28:04 +0000156
157 return newRanges;
Ted Kremenek45021952009-02-14 17:08:39 +0000158 }
159
Ted Kremenek9beefec2009-02-17 19:28:04 +0000160 RangeSet AddGT(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
161 PrimRangeSet newRanges = F.GetEmptySet();
Ted Kremenek45021952009-02-14 17:08:39 +0000162
Ted Kremenek9beefec2009-02-17 19:28:04 +0000163 for (PrimRangeSet::iterator i = begin(), e = end(); i != e; ++i) {
164 if (i->Includes(V) && i->To() > V)
165 newRanges = F.Add(newRanges, Range(BV.Add1(V), i->To()));
166 else if (i->From() > V)
167 newRanges = F.Add(newRanges, *i);
Ted Kremenek45021952009-02-14 17:08:39 +0000168 }
Ted Kremenek9beefec2009-02-17 19:28:04 +0000169
170 return newRanges;
Ted Kremenek45021952009-02-14 17:08:39 +0000171 }
172
Ted Kremenek9beefec2009-02-17 19:28:04 +0000173 RangeSet AddGE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
174 PrimRangeSet newRanges = F.GetEmptySet();
Ted Kremenek45021952009-02-14 17:08:39 +0000175
Ted Kremenek9beefec2009-02-17 19:28:04 +0000176 for (PrimRangeSet::iterator i = begin(), e = end(); i != e; ++i) {
177 // Strictly we should test for includes *V - 1, but no harm is
Ted Kremenek45021952009-02-14 17:08:39 +0000178 // done by this formulation
Ted Kremenek9beefec2009-02-17 19:28:04 +0000179 if (i->Includes(V))
180 newRanges = F.Add(newRanges, Range(V, i->To()));
181 else if (i->From() >= V)
182 newRanges = F.Add(newRanges, *i);
Ted Kremenek45021952009-02-14 17:08:39 +0000183 }
184
Ted Kremenek9beefec2009-02-17 19:28:04 +0000185 return newRanges;
Ted Kremenek45021952009-02-14 17:08:39 +0000186 }
187
188 void Print(std::ostream &os) const {
Ted Kremenek9beefec2009-02-17 19:28:04 +0000189 bool isFirst = true;
Ted Kremenek45021952009-02-14 17:08:39 +0000190 os << "{ ";
Ted Kremenek9beefec2009-02-17 19:28:04 +0000191 for (iterator i = begin(), e = end(); i != e; ++i) {
192 if (isFirst)
193 isFirst = false;
194 else
Ted Kremenek45021952009-02-14 17:08:39 +0000195 os << ", ";
Ted Kremenek9beefec2009-02-17 19:28:04 +0000196
Ted Kremenek45021952009-02-14 17:08:39 +0000197 os << '[' << i->From().toString(10) << ", " << i->To().toString(10)
198 << ']';
199 }
Ted Kremenek9beefec2009-02-17 19:28:04 +0000200 os << " }";
201 }
Ted Kremenek45021952009-02-14 17:08:39 +0000202
Ted Kremenek45021952009-02-14 17:08:39 +0000203 bool operator==(const RangeSet &other) const {
204 return ranges == other.ranges;
205 }
206};
207
Ted Kremenek9beefec2009-02-17 19:28:04 +0000208typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy;
Ted Kremenek45021952009-02-14 17:08:39 +0000209
210namespace clang {
211template<>
Ted Kremenek9beefec2009-02-17 19:28:04 +0000212struct GRStateTrait<ConstraintRange>
213 : public GRStatePartialTrait<ConstraintRangeTy> {
214 static inline void* GDMIndex() { return &ConstraintRangeIndex; }
Ted Kremenek45021952009-02-14 17:08:39 +0000215};
216}
217
218namespace {
219class VISIBILITY_HIDDEN RangeConstraintManager
220 : public SimpleConstraintManager {
Ted Kremenek9beefec2009-02-17 19:28:04 +0000221
222
223 RangeSet GetRange(GRStateRef state, SymbolRef sym);
224
Ted Kremenek45021952009-02-14 17:08:39 +0000225public:
226 RangeConstraintManager(GRStateManager& statemgr)
227 : SimpleConstraintManager(statemgr) {}
228
229 const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
230 const llvm::APSInt& V, bool& isFeasible);
231
232 const GRState* AssumeSymEQ(const GRState* St, SymbolRef sym,
233 const llvm::APSInt& V, bool& isFeasible);
234
235 const GRState* AssumeSymLT(const GRState* St, SymbolRef sym,
236 const llvm::APSInt& V, bool& isFeasible);
237
238 const GRState* AssumeSymGT(const GRState* St, SymbolRef sym,
239 const llvm::APSInt& V, bool& isFeasible);
240
241 const GRState* AssumeSymGE(const GRState* St, SymbolRef sym,
242 const llvm::APSInt& V, bool& isFeasible);
243
244 const GRState* AssumeSymLE(const GRState* St, SymbolRef sym,
245 const llvm::APSInt& V, bool& isFeasible);
246
Ted Kremenek45021952009-02-14 17:08:39 +0000247 const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const;
Ted Kremenek9beefec2009-02-17 19:28:04 +0000248
249 // FIXME: Refactor into SimpleConstraintManager?
250 bool isEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V) const {
251 const llvm::APSInt *i = getSymVal(St, sym);
252 return i ? *i == V : false;
253 }
Ted Kremenek45021952009-02-14 17:08:39 +0000254
Ted Kremenek45021952009-02-14 17:08:39 +0000255 const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
256
257 void print(const GRState* St, std::ostream& Out,
258 const char* nl, const char *sep);
259
260private:
Ted Kremenek9beefec2009-02-17 19:28:04 +0000261 RangeSet::Factory F;
Ted Kremenek45021952009-02-14 17:08:39 +0000262};
263
264} // end anonymous namespace
265
266ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager& StateMgr)
267{
268 return new RangeConstraintManager(StateMgr);
269}
270
Ted Kremenek45021952009-02-14 17:08:39 +0000271const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
272 SymbolRef sym) const {
Ted Kremenek9beefec2009-02-17 19:28:04 +0000273 const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym);
274 return T ? T->getConcreteValue() : NULL;
Ted Kremenek45021952009-02-14 17:08:39 +0000275}
276
277/// Scan all symbols referenced by the constraints. If the symbol is not alive
278/// as marked in LSymbols, mark it as dead in DSymbols.
279const GRState*
280RangeConstraintManager::RemoveDeadBindings(const GRState* St,
281 SymbolReaper& SymReaper) {
282 GRStateRef state(St, StateMgr);
283
Ted Kremenek9beefec2009-02-17 19:28:04 +0000284 ConstraintRangeTy CR = state.get<ConstraintRange>();
285 ConstraintRangeTy::Factory& CRFactory = state.get_context<ConstraintRange>();
Ted Kremenek45021952009-02-14 17:08:39 +0000286
Ted Kremenek9beefec2009-02-17 19:28:04 +0000287 for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) {
Ted Kremenek45021952009-02-14 17:08:39 +0000288 SymbolRef sym = I.getKey();
289 if (SymReaper.maybeDead(sym))
290 CR = CRFactory.Remove(CR, sym);
291 }
292
Ted Kremenek9beefec2009-02-17 19:28:04 +0000293 return state.set<ConstraintRange>(CR);
Ted Kremenek45021952009-02-14 17:08:39 +0000294}
295
Ted Kremenek9beefec2009-02-17 19:28:04 +0000296//===------------------------------------------------------------------------===
297// AssumeSymX methods: public interface for RangeConstraintManager.
298//===------------------------------------------------------------------------===/
299
300RangeSet
301RangeConstraintManager::GetRange(GRStateRef state, SymbolRef sym) {
302 if (ConstraintRangeTy::data_type* V = state.get<ConstraintRange>(sym))
303 return *V;
304
305 // Lazily generate a new RangeSet representing all possible values for the
306 // given symbol type.
307 QualType T = state.getSymbolManager().getType(sym);
308 BasicValueFactory& BV = state.getBasicVals();
309 return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T));
310}
311
312//===------------------------------------------------------------------------===
313// AssumeSymX methods: public interface for RangeConstraintManager.
314//===------------------------------------------------------------------------===/
315
316#define AssumeX(OP)\
317const GRState*\
318RangeConstraintManager::AssumeSym ## OP(const GRState* St, SymbolRef sym,\
319 const llvm::APSInt& V, bool& isFeasible){\
320 GRStateRef state(St, StateMgr);\
321 const RangeSet& R = GetRange(state, sym).Add##OP(state.getBasicVals(), F, V);\
322 isFeasible = !R.isEmpty();\
323 return isFeasible ? state.set<ConstraintRange>(sym, R).getState() : 0;\
324}
325
326AssumeX(EQ)
327AssumeX(NE)
328AssumeX(LT)
329AssumeX(GT)
330AssumeX(LE)
331AssumeX(GE)
332
333//===------------------------------------------------------------------------===
334// Pretty-printing.
335//===------------------------------------------------------------------------===/
336
Ted Kremenek45021952009-02-14 17:08:39 +0000337void RangeConstraintManager::print(const GRState* St, std::ostream& Out,
338 const char* nl, const char *sep) {
Ted Kremenekdd28d002009-02-16 18:42:56 +0000339
Ted Kremenek9beefec2009-02-17 19:28:04 +0000340 ConstraintRangeTy Ranges = St->get<ConstraintRange>();
Ted Kremenekdd28d002009-02-16 18:42:56 +0000341
342 if (Ranges.isEmpty())
343 return;
344
345 Out << nl << sep << "ranges of symbol values:";
346
Ted Kremenek9beefec2009-02-17 19:28:04 +0000347 for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
Ted Kremenekdd28d002009-02-16 18:42:56 +0000348 Out << nl << " $" << I.getKey() << " : ";
349 I.getData().Print(Out);
Ted Kremenek45021952009-02-14 17:08:39 +0000350 }
Ted Kremenek45021952009-02-14 17:08:39 +0000351}