blob: e6f940e57cc28f6c5aa82ab34752fd25a03d4c3e [file] [log] [blame]
Ted Kremenek45021952009-02-14 17:08:39 +00001//== 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
15#include "SimpleConstraintManager.h"
16#include "clang/Analysis/PathSensitive/GRExprEngine.h"
17#include "clang/Analysis/PathSensitive/GRState.h"
18
19namespace clang {
20
21SimpleConstraintManager::~SimpleConstraintManager() {}
22
Ted Kremenek66b52712009-03-11 02:22:59 +000023bool SimpleConstraintManager::canReasonAbout(SVal X) const {
Ted Kremenek7de20fe2009-03-11 02:29:48 +000024 if (nonloc::SymIntConstraintVal *Y = dyn_cast<nonloc::SymIntConstraintVal>(&X)) {
25 const SymIntConstraint& C = Y->getConstraint();
26 switch (C.getOpcode()) {
27 // We don't reason yet about bitwise-constraints on symbolic values.
28 case BinaryOperator::And:
29 case BinaryOperator::Or:
30 case BinaryOperator::Xor:
31 return false;
Ted Kremenek68ac94a2009-03-23 17:10:25 +000032 // We don't reason yet about arithmetic constraints on symbolic values.
33 case BinaryOperator::Mul:
34 case BinaryOperator::Div:
35 case BinaryOperator::Rem:
36 case BinaryOperator::Add:
37 case BinaryOperator::Sub:
38 case BinaryOperator::Shl:
39 case BinaryOperator::Shr:
40 return false;
41
42 // All other cases.
Ted Kremenek7de20fe2009-03-11 02:29:48 +000043 default:
44 return true;
45 }
46 }
47
Ted Kremenek66b52712009-03-11 02:22:59 +000048 return true;
49}
50
Ted Kremenek45021952009-02-14 17:08:39 +000051const GRState*
52SimpleConstraintManager::Assume(const GRState* St, SVal Cond, bool Assumption,
53 bool& isFeasible) {
54 if (Cond.isUnknown()) {
55 isFeasible = true;
56 return St;
57 }
58
59 if (isa<NonLoc>(Cond))
60 return Assume(St, cast<NonLoc>(Cond), Assumption, isFeasible);
61 else
62 return Assume(St, cast<Loc>(Cond), Assumption, isFeasible);
63}
64
65const GRState*
66SimpleConstraintManager::Assume(const GRState* St, Loc Cond, bool Assumption,
67 bool& isFeasible) {
68 St = AssumeAux(St, Cond, Assumption, isFeasible);
69
70 if (!isFeasible)
71 return St;
72
73 // EvalAssume is used to call into the GRTransferFunction object to perform
74 // any checker-specific update of the state based on this assumption being
75 // true or false.
76 return StateMgr.getTransferFuncs().EvalAssume(StateMgr, St, Cond, Assumption,
77 isFeasible);
78}
79
80const GRState*
81SimpleConstraintManager::AssumeAux(const GRState* St, Loc Cond, bool Assumption,
82 bool& isFeasible) {
83 BasicValueFactory& BasicVals = StateMgr.getBasicVals();
84
85 switch (Cond.getSubKind()) {
86 default:
87 assert (false && "'Assume' not implemented for this Loc.");
88 return St;
89
90 case loc::SymbolValKind:
91 if (Assumption)
92 return AssumeSymNE(St, cast<loc::SymbolVal>(Cond).getSymbol(),
93 BasicVals.getZeroWithPtrWidth(), isFeasible);
94 else
95 return AssumeSymEQ(St, cast<loc::SymbolVal>(Cond).getSymbol(),
96 BasicVals.getZeroWithPtrWidth(), isFeasible);
97
98 case loc::MemRegionKind: {
99 // FIXME: Should this go into the storemanager?
100
101 const MemRegion* R = cast<loc::MemRegionVal>(Cond).getRegion();
102 const SubRegion* SubR = dyn_cast<SubRegion>(R);
103
104 while (SubR) {
105 // FIXME: now we only find the first symbolic region.
106 if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(SubR))
107 return AssumeAux(St, loc::SymbolVal(SymR->getSymbol()), Assumption,
108 isFeasible);
109 SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
110 }
111
112 // FALL-THROUGH.
113 }
114
115 case loc::FuncValKind:
116 case loc::GotoLabelKind:
117 isFeasible = Assumption;
118 return St;
119
120 case loc::ConcreteIntKind: {
121 bool b = cast<loc::ConcreteInt>(Cond).getValue() != 0;
122 isFeasible = b ? Assumption : !Assumption;
123 return St;
124 }
125 } // end switch
126}
127
128const GRState*
129SimpleConstraintManager::Assume(const GRState* St, NonLoc Cond, bool Assumption,
130 bool& isFeasible) {
131 St = AssumeAux(St, Cond, Assumption, isFeasible);
132
133 if (!isFeasible)
134 return St;
135
136 // EvalAssume is used to call into the GRTransferFunction object to perform
137 // any checker-specific update of the state based on this assumption being
138 // true or false.
139 return StateMgr.getTransferFuncs().EvalAssume(StateMgr, St, Cond, Assumption,
140 isFeasible);
141}
142
143const GRState*
144SimpleConstraintManager::AssumeAux(const GRState* St,NonLoc Cond,
145 bool Assumption, bool& isFeasible) {
146 BasicValueFactory& BasicVals = StateMgr.getBasicVals();
147 SymbolManager& SymMgr = StateMgr.getSymbolManager();
148
149 switch (Cond.getSubKind()) {
150 default:
151 assert(false && "'Assume' not implemented for this NonLoc");
152
153 case nonloc::SymbolValKind: {
154 nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
155 SymbolRef sym = SV.getSymbol();
156 QualType T = SymMgr.getType(sym);
157
158 if (Assumption)
159 return AssumeSymNE(St, sym, BasicVals.getValue(0, T), isFeasible);
160 else
161 return AssumeSymEQ(St, sym, BasicVals.getValue(0, T), isFeasible);
162 }
163
164 case nonloc::SymIntConstraintValKind:
165 return
166 AssumeSymInt(St, Assumption,
167 cast<nonloc::SymIntConstraintVal>(Cond).getConstraint(),
168 isFeasible);
169
170 case nonloc::ConcreteIntKind: {
171 bool b = cast<nonloc::ConcreteInt>(Cond).getValue() != 0;
172 isFeasible = b ? Assumption : !Assumption;
173 return St;
174 }
175
176 case nonloc::LocAsIntegerKind:
177 return AssumeAux(St, cast<nonloc::LocAsInteger>(Cond).getLoc(),
178 Assumption, isFeasible);
179 } // end switch
180}
181
182const GRState*
183SimpleConstraintManager::AssumeSymInt(const GRState* St, bool Assumption,
184 const SymIntConstraint& C,
185 bool& isFeasible) {
186
187 switch (C.getOpcode()) {
188 default:
189 // No logic yet for other operators.
190 isFeasible = true;
191 return St;
192
193 case BinaryOperator::EQ:
194 if (Assumption)
195 return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible);
196 else
197 return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible);
198
199 case BinaryOperator::NE:
200 if (Assumption)
201 return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible);
202 else
203 return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible);
204
205 case BinaryOperator::GT:
206 if (Assumption)
207 return AssumeSymGT(St, C.getSymbol(), C.getInt(), isFeasible);
208 else
209 return AssumeSymLE(St, C.getSymbol(), C.getInt(), isFeasible);
210
211 case BinaryOperator::GE:
212 if (Assumption)
213 return AssumeSymGE(St, C.getSymbol(), C.getInt(), isFeasible);
214 else
215 return AssumeSymLT(St, C.getSymbol(), C.getInt(), isFeasible);
216
217 case BinaryOperator::LT:
218 if (Assumption)
219 return AssumeSymLT(St, C.getSymbol(), C.getInt(), isFeasible);
220 else
221 return AssumeSymGE(St, C.getSymbol(), C.getInt(), isFeasible);
222
223 case BinaryOperator::LE:
224 if (Assumption)
225 return AssumeSymLE(St, C.getSymbol(), C.getInt(), isFeasible);
226 else
227 return AssumeSymGT(St, C.getSymbol(), C.getInt(), isFeasible);
228 } // end switch
229}
230
231const GRState*
232SimpleConstraintManager::AssumeInBound(const GRState* St, SVal Idx,
233 SVal UpperBound, bool Assumption,
234 bool& isFeasible) {
235 // Only support ConcreteInt for now.
236 if (!(isa<nonloc::ConcreteInt>(Idx) && isa<nonloc::ConcreteInt>(UpperBound))){
237 isFeasible = true;
238 return St;
239 }
240
241 const llvm::APSInt& Zero = getBasicVals().getZeroWithPtrWidth(false);
242 llvm::APSInt IdxV = cast<nonloc::ConcreteInt>(Idx).getValue();
243 // IdxV might be too narrow.
244 if (IdxV.getBitWidth() < Zero.getBitWidth())
245 IdxV.extend(Zero.getBitWidth());
246 // UBV might be too narrow, too.
247 llvm::APSInt UBV = cast<nonloc::ConcreteInt>(UpperBound).getValue();
248 if (UBV.getBitWidth() < Zero.getBitWidth())
249 UBV.extend(Zero.getBitWidth());
250
251 bool InBound = (Zero <= IdxV) && (IdxV < UBV);
252
253 isFeasible = Assumption ? InBound : !InBound;
254
255 return St;
256}
257
258} // end of namespace clang