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