]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Core / SymbolManager.cpp
1 //== SymbolManager.h - Management of Symbolic Values ------------*- 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 SymbolManager, a class that manages symbolic values
11 //  created for use by ExprEngine and related classes.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
16 #include "clang/Analysis/Analyses/LiveVariables.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
19 #include "llvm/Support/raw_ostream.h"
20
21 using namespace clang;
22 using namespace ento;
23
24 void SymExpr::dump() const {
25   dumpToStream(llvm::errs());
26 }
27
28 static void print(raw_ostream &os, BinaryOperator::Opcode Op) {
29   switch (Op) {
30     default:
31       llvm_unreachable("operator printing not implemented");
32     case BO_Mul: os << '*'  ; break;
33     case BO_Div: os << '/'  ; break;
34     case BO_Rem: os << '%'  ; break;
35     case BO_Add: os << '+'  ; break;
36     case BO_Sub: os << '-'  ; break;
37     case BO_Shl: os << "<<" ; break;
38     case BO_Shr: os << ">>" ; break;
39     case BO_LT:  os << "<"  ; break;
40     case BO_GT:  os << '>'  ; break;
41     case BO_LE:  os << "<=" ; break;
42     case BO_GE:  os << ">=" ; break;
43     case BO_EQ:  os << "==" ; break;
44     case BO_NE:  os << "!=" ; break;
45     case BO_And: os << '&'  ; break;
46     case BO_Xor: os << '^'  ; break;
47     case BO_Or:  os << '|'  ; break;
48   }
49 }
50
51 void SymIntExpr::dumpToStream(raw_ostream &os) const {
52   os << '(';
53   getLHS()->dumpToStream(os);
54   os << ") ";
55   print(os, getOpcode());
56   os << ' ' << getRHS().getZExtValue();
57   if (getRHS().isUnsigned()) os << 'U';
58 }
59
60 void SymSymExpr::dumpToStream(raw_ostream &os) const {
61   os << '(';
62   getLHS()->dumpToStream(os);
63   os << ") ";
64   os << '(';
65   getRHS()->dumpToStream(os);
66   os << ')';
67 }
68
69 void SymbolConjured::dumpToStream(raw_ostream &os) const {
70   os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
71 }
72
73 void SymbolDerived::dumpToStream(raw_ostream &os) const {
74   os << "derived_$" << getSymbolID() << '{'
75      << getParentSymbol() << ',' << getRegion() << '}';
76 }
77
78 void SymbolExtent::dumpToStream(raw_ostream &os) const {
79   os << "extent_$" << getSymbolID() << '{' << getRegion() << '}';
80 }
81
82 void SymbolMetadata::dumpToStream(raw_ostream &os) const {
83   os << "meta_$" << getSymbolID() << '{'
84      << getRegion() << ',' << T.getAsString() << '}';
85 }
86
87 void SymbolRegionValue::dumpToStream(raw_ostream &os) const {
88   os << "reg_$" << getSymbolID() << "<" << R << ">";
89 }
90
91 const SymbolRegionValue*
92 SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
93   llvm::FoldingSetNodeID profile;
94   SymbolRegionValue::Profile(profile, R);
95   void *InsertPos;
96   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
97   if (!SD) {
98     SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
99     new (SD) SymbolRegionValue(SymbolCounter, R);
100     DataSet.InsertNode(SD, InsertPos);
101     ++SymbolCounter;
102   }
103
104   return cast<SymbolRegionValue>(SD);
105 }
106
107 const SymbolConjured*
108 SymbolManager::getConjuredSymbol(const Stmt *E, QualType T, unsigned Count,
109                                  const void *SymbolTag) {
110
111   llvm::FoldingSetNodeID profile;
112   SymbolConjured::Profile(profile, E, T, Count, SymbolTag);
113   void *InsertPos;
114   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
115   if (!SD) {
116     SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
117     new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag);
118     DataSet.InsertNode(SD, InsertPos);
119     ++SymbolCounter;
120   }
121
122   return cast<SymbolConjured>(SD);
123 }
124
125 const SymbolDerived*
126 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
127                                 const TypedValueRegion *R) {
128
129   llvm::FoldingSetNodeID profile;
130   SymbolDerived::Profile(profile, parentSymbol, R);
131   void *InsertPos;
132   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
133   if (!SD) {
134     SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
135     new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
136     DataSet.InsertNode(SD, InsertPos);
137     ++SymbolCounter;
138   }
139
140   return cast<SymbolDerived>(SD);
141 }
142
143 const SymbolExtent*
144 SymbolManager::getExtentSymbol(const SubRegion *R) {
145   llvm::FoldingSetNodeID profile;
146   SymbolExtent::Profile(profile, R);
147   void *InsertPos;
148   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
149   if (!SD) {
150     SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
151     new (SD) SymbolExtent(SymbolCounter, R);
152     DataSet.InsertNode(SD, InsertPos);
153     ++SymbolCounter;
154   }
155
156   return cast<SymbolExtent>(SD);
157 }
158
159 const SymbolMetadata*
160 SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
161                                  unsigned Count, const void *SymbolTag) {
162
163   llvm::FoldingSetNodeID profile;
164   SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag);
165   void *InsertPos;
166   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
167   if (!SD) {
168     SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
169     new (SD) SymbolMetadata(SymbolCounter, R, S, T, Count, SymbolTag);
170     DataSet.InsertNode(SD, InsertPos);
171     ++SymbolCounter;
172   }
173
174   return cast<SymbolMetadata>(SD);
175 }
176
177 const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
178                                                BinaryOperator::Opcode op,
179                                                const llvm::APSInt& v,
180                                                QualType t) {
181   llvm::FoldingSetNodeID ID;
182   SymIntExpr::Profile(ID, lhs, op, v, t);
183   void *InsertPos;
184   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
185
186   if (!data) {
187     data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
188     new (data) SymIntExpr(lhs, op, v, t);
189     DataSet.InsertNode(data, InsertPos);
190   }
191
192   return cast<SymIntExpr>(data);
193 }
194
195 const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
196                                                BinaryOperator::Opcode op,
197                                                const SymExpr *rhs,
198                                                QualType t) {
199   llvm::FoldingSetNodeID ID;
200   SymSymExpr::Profile(ID, lhs, op, rhs, t);
201   void *InsertPos;
202   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
203
204   if (!data) {
205     data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
206     new (data) SymSymExpr(lhs, op, rhs, t);
207     DataSet.InsertNode(data, InsertPos);
208   }
209
210   return cast<SymSymExpr>(data);
211 }
212
213 QualType SymbolConjured::getType(ASTContext&) const {
214   return T;
215 }
216
217 QualType SymbolDerived::getType(ASTContext &Ctx) const {
218   return R->getValueType();
219 }
220
221 QualType SymbolExtent::getType(ASTContext &Ctx) const {
222   return Ctx.getSizeType();
223 }
224
225 QualType SymbolMetadata::getType(ASTContext&) const {
226   return T;
227 }
228
229 QualType SymbolRegionValue::getType(ASTContext &C) const {
230   return R->getValueType();
231 }
232
233 SymbolManager::~SymbolManager() {
234   for (SymbolDependTy::const_iterator I = SymbolDependencies.begin(),
235        E = SymbolDependencies.end(); I != E; ++I) {
236     delete I->second;
237   }
238
239 }
240
241 bool SymbolManager::canSymbolicate(QualType T) {
242   T = T.getCanonicalType();
243
244   if (Loc::isLocType(T))
245     return true;
246
247   if (T->isIntegerType())
248     return T->isScalarType();
249
250   if (T->isRecordType() && !T->isUnionType())
251     return true;
252
253   return false;
254 }
255
256 void SymbolManager::addSymbolDependency(const SymbolRef Primary,
257                                         const SymbolRef Dependent) {
258   SymbolDependTy::iterator I = SymbolDependencies.find(Primary);
259   SymbolRefSmallVectorTy *dependencies = 0;
260   if (I == SymbolDependencies.end()) {
261     dependencies = new SymbolRefSmallVectorTy();
262     SymbolDependencies[Primary] = dependencies;
263   } else {
264     dependencies = I->second;
265   }
266   dependencies->push_back(Dependent);
267 }
268
269 const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols(
270                                                      const SymbolRef Primary) {
271   SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary);
272   if (I == SymbolDependencies.end())
273     return 0;
274   return I->second;
275 }
276
277 void SymbolReaper::markDependentsLive(SymbolRef sym) {
278   // Do not mark dependents more then once.
279   SymbolMapTy::iterator LI = TheLiving.find(sym);
280   assert(LI != TheLiving.end() && "The primary symbol is not live.");
281   if (LI->second == HaveMarkedDependents)
282     return;
283   LI->second = HaveMarkedDependents;
284
285   if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) {
286     for (SymbolRefSmallVectorTy::const_iterator I = Deps->begin(),
287                                                 E = Deps->end(); I != E; ++I) {
288       if (TheLiving.find(*I) != TheLiving.end())
289         continue;
290       markLive(*I);
291     }
292   }
293 }
294
295 void SymbolReaper::markLive(SymbolRef sym) {
296   TheLiving[sym] = NotProcessed;
297   TheDead.erase(sym);
298   markDependentsLive(sym);
299 }
300
301 void SymbolReaper::markLive(const MemRegion *region) {
302   RegionRoots.insert(region);
303 }
304
305 void SymbolReaper::markInUse(SymbolRef sym) {
306   if (isa<SymbolMetadata>(sym))
307     MetadataInUse.insert(sym);
308 }
309
310 bool SymbolReaper::maybeDead(SymbolRef sym) {
311   if (isLive(sym))
312     return false;
313
314   TheDead.insert(sym);
315   return true;
316 }
317
318 bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
319   if (RegionRoots.count(MR))
320     return true;
321   
322   MR = MR->getBaseRegion();
323
324   if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
325     return isLive(SR->getSymbol());
326
327   if (const VarRegion *VR = dyn_cast<VarRegion>(MR))
328     return isLive(VR, true);
329
330   // FIXME: This is a gross over-approximation. What we really need is a way to
331   // tell if anything still refers to this region. Unlike SymbolicRegions,
332   // AllocaRegions don't have associated symbols, though, so we don't actually
333   // have a way to track their liveness.
334   if (isa<AllocaRegion>(MR))
335     return true;
336
337   if (isa<CXXThisRegion>(MR))
338     return true;
339
340   if (isa<MemSpaceRegion>(MR))
341     return true;
342
343   return false;
344 }
345
346 bool SymbolReaper::isLive(SymbolRef sym) {
347   if (TheLiving.count(sym)) {
348     markDependentsLive(sym);
349     return true;
350   }
351
352   if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
353     if (isLive(derived->getParentSymbol())) {
354       markLive(sym);
355       return true;
356     }
357     return false;
358   }
359
360   if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) {
361     if (isLiveRegion(extent->getRegion())) {
362       markLive(sym);
363       return true;
364     }
365     return false;
366   }
367
368   if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) {
369     if (MetadataInUse.count(sym)) {
370       if (isLiveRegion(metadata->getRegion())) {
371         markLive(sym);
372         MetadataInUse.erase(sym);
373         return true;
374       }
375     }
376     return false;
377   }
378
379   // Interogate the symbol.  It may derive from an input value to
380   // the analyzed function/method.
381   return isa<SymbolRegionValue>(sym);
382 }
383
384 bool SymbolReaper::isLive(const Stmt *ExprVal) const {
385   return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal);
386 }
387
388 bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
389   const StackFrameContext *VarContext = VR->getStackFrame();
390   const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
391
392   if (VarContext == CurrentContext) {
393     if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl()))
394       return true;
395
396     if (!includeStoreBindings)
397       return false;
398     
399     unsigned &cachedQuery =
400       const_cast<SymbolReaper*>(this)->includedRegionCache[VR];
401
402     if (cachedQuery) {
403       return cachedQuery == 1;
404     }
405
406     // Query the store to see if the region occurs in any live bindings.
407     if (Store store = reapedStore.getStore()) {
408       bool hasRegion = 
409         reapedStore.getStoreManager().includedInBindings(store, VR);
410       cachedQuery = hasRegion ? 1 : 2;
411       return hasRegion;
412     }
413     
414     return false;
415   }
416
417   return VarContext->isParentOf(CurrentContext);
418 }
419
420 SymbolVisitor::~SymbolVisitor() {}