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