• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "llvm/Support/raw_ostream.h"
19 
20 using namespace clang;
21 using namespace ento;
22 
dump() const23 void SymExpr::dump() const {
24   dumpToStream(llvm::errs());
25 }
26 
print(llvm::raw_ostream & os,BinaryOperator::Opcode Op)27 static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
28   switch (Op) {
29     default:
30       assert(false && "operator printing not implemented");
31       break;
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 
dumpToStream(llvm::raw_ostream & os) const51 void SymIntExpr::dumpToStream(llvm::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 
dumpToStream(llvm::raw_ostream & os) const60 void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const {
61   os << '(';
62   getLHS()->dumpToStream(os);
63   os << ") ";
64   os << '(';
65   getRHS()->dumpToStream(os);
66   os << ')';
67 }
68 
dumpToStream(llvm::raw_ostream & os) const69 void SymbolConjured::dumpToStream(llvm::raw_ostream& os) const {
70   os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
71 }
72 
dumpToStream(llvm::raw_ostream & os) const73 void SymbolDerived::dumpToStream(llvm::raw_ostream& os) const {
74   os << "derived_$" << getSymbolID() << '{'
75      << getParentSymbol() << ',' << getRegion() << '}';
76 }
77 
dumpToStream(llvm::raw_ostream & os) const78 void SymbolExtent::dumpToStream(llvm::raw_ostream& os) const {
79   os << "extent_$" << getSymbolID() << '{' << getRegion() << '}';
80 }
81 
dumpToStream(llvm::raw_ostream & os) const82 void SymbolMetadata::dumpToStream(llvm::raw_ostream& os) const {
83   os << "meta_$" << getSymbolID() << '{'
84      << getRegion() << ',' << T.getAsString() << '}';
85 }
86 
dumpToStream(llvm::raw_ostream & os) const87 void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const {
88   os << "reg_$" << getSymbolID() << "<" << R << ">";
89 }
90 
91 const SymbolRegionValue*
getRegionValueSymbol(const TypedRegion * R)92 SymbolManager::getRegionValueSymbol(const TypedRegion* 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*
getConjuredSymbol(const Stmt * E,QualType T,unsigned Count,const void * SymbolTag)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*
getDerivedSymbol(SymbolRef parentSymbol,const TypedRegion * R)126 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
127                                 const TypedRegion *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*
getExtentSymbol(const SubRegion * R)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*
getMetadataSymbol(const MemRegion * R,const Stmt * S,QualType T,unsigned Count,const void * SymbolTag)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 
getSymIntExpr(const SymExpr * lhs,BinaryOperator::Opcode op,const llvm::APSInt & v,QualType t)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 
getSymSymExpr(const SymExpr * lhs,BinaryOperator::Opcode op,const SymExpr * rhs,QualType t)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 
getType(ASTContext &) const213 QualType SymbolConjured::getType(ASTContext&) const {
214   return T;
215 }
216 
getType(ASTContext & Ctx) const217 QualType SymbolDerived::getType(ASTContext& Ctx) const {
218   return R->getValueType();
219 }
220 
getType(ASTContext & Ctx) const221 QualType SymbolExtent::getType(ASTContext& Ctx) const {
222   return Ctx.getSizeType();
223 }
224 
getType(ASTContext &) const225 QualType SymbolMetadata::getType(ASTContext&) const {
226   return T;
227 }
228 
getType(ASTContext & C) const229 QualType SymbolRegionValue::getType(ASTContext& C) const {
230   return R->getValueType();
231 }
232 
~SymbolManager()233 SymbolManager::~SymbolManager() {}
234 
canSymbolicate(QualType T)235 bool SymbolManager::canSymbolicate(QualType T) {
236   T = T.getCanonicalType();
237 
238   if (Loc::isLocType(T))
239     return true;
240 
241   if (T->isIntegerType())
242     return T->isScalarType();
243 
244   if (T->isRecordType() && !T->isUnionType())
245     return true;
246 
247   return false;
248 }
249 
markLive(SymbolRef sym)250 void SymbolReaper::markLive(SymbolRef sym) {
251   TheLiving.insert(sym);
252   TheDead.erase(sym);
253 }
254 
markInUse(SymbolRef sym)255 void SymbolReaper::markInUse(SymbolRef sym) {
256   if (isa<SymbolMetadata>(sym))
257     MetadataInUse.insert(sym);
258 }
259 
maybeDead(SymbolRef sym)260 bool SymbolReaper::maybeDead(SymbolRef sym) {
261   if (isLive(sym))
262     return false;
263 
264   TheDead.insert(sym);
265   return true;
266 }
267 
IsLiveRegion(SymbolReaper & Reaper,const MemRegion * MR)268 static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) {
269   MR = MR->getBaseRegion();
270 
271   if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
272     return Reaper.isLive(SR->getSymbol());
273 
274   if (const VarRegion *VR = dyn_cast<VarRegion>(MR))
275     return Reaper.isLive(VR);
276 
277   // FIXME: This is a gross over-approximation. What we really need is a way to
278   // tell if anything still refers to this region. Unlike SymbolicRegions,
279   // AllocaRegions don't have associated symbols, though, so we don't actually
280   // have a way to track their liveness.
281   if (isa<AllocaRegion>(MR))
282     return true;
283 
284   if (isa<CXXThisRegion>(MR))
285     return true;
286 
287   if (isa<MemSpaceRegion>(MR))
288     return true;
289 
290   return false;
291 }
292 
isLive(SymbolRef sym)293 bool SymbolReaper::isLive(SymbolRef sym) {
294   if (TheLiving.count(sym))
295     return true;
296 
297   if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
298     if (isLive(derived->getParentSymbol())) {
299       markLive(sym);
300       return true;
301     }
302     return false;
303   }
304 
305   if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) {
306     if (IsLiveRegion(*this, extent->getRegion())) {
307       markLive(sym);
308       return true;
309     }
310     return false;
311   }
312 
313   if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) {
314     if (MetadataInUse.count(sym)) {
315       if (IsLiveRegion(*this, metadata->getRegion())) {
316         markLive(sym);
317         MetadataInUse.erase(sym);
318         return true;
319       }
320     }
321     return false;
322   }
323 
324   // Interogate the symbol.  It may derive from an input value to
325   // the analyzed function/method.
326   return isa<SymbolRegionValue>(sym);
327 }
328 
isLive(const Stmt * ExprVal) const329 bool SymbolReaper::isLive(const Stmt* ExprVal) const {
330   return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
331       isLive(Loc, ExprVal);
332 }
333 
isLive(const VarRegion * VR) const334 bool SymbolReaper::isLive(const VarRegion *VR) const {
335   const StackFrameContext *VarContext = VR->getStackFrame();
336   const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
337 
338   if (VarContext == CurrentContext)
339     return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
340         isLive(Loc, VR->getDecl());
341 
342   return VarContext->isParentOf(CurrentContext);
343 }
344 
~SymbolVisitor()345 SymbolVisitor::~SymbolVisitor() {}
346