1e5dd7070Spatrick //===- SymbolManager.h - Management of Symbolic Values --------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file defines SymbolManager, a class that manages symbolic values
10e5dd7070Spatrick // created for use by ExprEngine and related classes.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
15e5dd7070Spatrick #include "clang/AST/ASTContext.h"
16e5dd7070Spatrick #include "clang/AST/Expr.h"
17a9ac8606Spatrick #include "clang/AST/StmtObjC.h"
18e5dd7070Spatrick #include "clang/Analysis/Analyses/LiveVariables.h"
19e5dd7070Spatrick #include "clang/Analysis/AnalysisDeclContext.h"
20e5dd7070Spatrick #include "clang/Basic/LLVM.h"
21e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
22e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
23e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
24e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
25e5dd7070Spatrick #include "llvm/ADT/FoldingSet.h"
26e5dd7070Spatrick #include "llvm/ADT/STLExtras.h"
27e5dd7070Spatrick #include "llvm/Support/Casting.h"
28e5dd7070Spatrick #include "llvm/Support/Compiler.h"
29e5dd7070Spatrick #include "llvm/Support/ErrorHandling.h"
30e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
31e5dd7070Spatrick #include <cassert>
32e5dd7070Spatrick
33e5dd7070Spatrick using namespace clang;
34e5dd7070Spatrick using namespace ento;
35e5dd7070Spatrick
anchor()36e5dd7070Spatrick void SymExpr::anchor() {}
37e5dd7070Spatrick
getKindStr() const38a9ac8606Spatrick StringRef SymbolConjured::getKindStr() const { return "conj_$"; }
getKindStr() const39a9ac8606Spatrick StringRef SymbolDerived::getKindStr() const { return "derived_$"; }
getKindStr() const40a9ac8606Spatrick StringRef SymbolExtent::getKindStr() const { return "extent_$"; }
getKindStr() const41a9ac8606Spatrick StringRef SymbolMetadata::getKindStr() const { return "meta_$"; }
getKindStr() const42a9ac8606Spatrick StringRef SymbolRegionValue::getKindStr() const { return "reg_$"; }
43a9ac8606Spatrick
dump() const44ec727ea7Spatrick LLVM_DUMP_METHOD void SymExpr::dump() const { dumpToStream(llvm::errs()); }
45ec727ea7Spatrick
dumpToStreamImpl(raw_ostream & OS,const SymExpr * Sym)46ec727ea7Spatrick void BinarySymExpr::dumpToStreamImpl(raw_ostream &OS, const SymExpr *Sym) {
47ec727ea7Spatrick OS << '(';
48ec727ea7Spatrick Sym->dumpToStream(OS);
49ec727ea7Spatrick OS << ')';
50e5dd7070Spatrick }
51e5dd7070Spatrick
dumpToStreamImpl(raw_ostream & OS,const llvm::APSInt & Value)52ec727ea7Spatrick void BinarySymExpr::dumpToStreamImpl(raw_ostream &OS,
53ec727ea7Spatrick const llvm::APSInt &Value) {
54ec727ea7Spatrick if (Value.isUnsigned())
55ec727ea7Spatrick OS << Value.getZExtValue();
56e5dd7070Spatrick else
57ec727ea7Spatrick OS << Value.getSExtValue();
58ec727ea7Spatrick if (Value.isUnsigned())
59ec727ea7Spatrick OS << 'U';
60e5dd7070Spatrick }
61e5dd7070Spatrick
dumpToStreamImpl(raw_ostream & OS,BinaryOperator::Opcode Op)62ec727ea7Spatrick void BinarySymExpr::dumpToStreamImpl(raw_ostream &OS,
63ec727ea7Spatrick BinaryOperator::Opcode Op) {
64ec727ea7Spatrick OS << ' ' << BinaryOperator::getOpcodeStr(Op) << ' ';
65e5dd7070Spatrick }
66e5dd7070Spatrick
dumpToStream(raw_ostream & os) const67e5dd7070Spatrick void SymbolCast::dumpToStream(raw_ostream &os) const {
68*12c85518Srobert os << '(' << ToTy << ") (";
69e5dd7070Spatrick Operand->dumpToStream(os);
70e5dd7070Spatrick os << ')';
71e5dd7070Spatrick }
72e5dd7070Spatrick
dumpToStream(raw_ostream & os) const73*12c85518Srobert void UnarySymExpr::dumpToStream(raw_ostream &os) const {
74*12c85518Srobert os << UnaryOperator::getOpcodeStr(Op);
75*12c85518Srobert bool Binary = isa<BinarySymExpr>(Operand);
76*12c85518Srobert if (Binary)
77*12c85518Srobert os << '(';
78*12c85518Srobert Operand->dumpToStream(os);
79*12c85518Srobert if (Binary)
80*12c85518Srobert os << ')';
81*12c85518Srobert }
82*12c85518Srobert
dumpToStream(raw_ostream & os) const83e5dd7070Spatrick void SymbolConjured::dumpToStream(raw_ostream &os) const {
84*12c85518Srobert os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID();
85e5dd7070Spatrick if (S)
86e5dd7070Spatrick os << ", S" << S->getID(LCtx->getDecl()->getASTContext());
87e5dd7070Spatrick else
88e5dd7070Spatrick os << ", no stmt";
89e5dd7070Spatrick os << ", #" << Count << '}';
90e5dd7070Spatrick }
91e5dd7070Spatrick
dumpToStream(raw_ostream & os) const92e5dd7070Spatrick void SymbolDerived::dumpToStream(raw_ostream &os) const {
93a9ac8606Spatrick os << getKindStr() << getSymbolID() << '{' << getParentSymbol() << ','
94a9ac8606Spatrick << getRegion() << '}';
95e5dd7070Spatrick }
96e5dd7070Spatrick
dumpToStream(raw_ostream & os) const97e5dd7070Spatrick void SymbolExtent::dumpToStream(raw_ostream &os) const {
98a9ac8606Spatrick os << getKindStr() << getSymbolID() << '{' << getRegion() << '}';
99e5dd7070Spatrick }
100e5dd7070Spatrick
dumpToStream(raw_ostream & os) const101e5dd7070Spatrick void SymbolMetadata::dumpToStream(raw_ostream &os) const {
102*12c85518Srobert os << getKindStr() << getSymbolID() << '{' << getRegion() << ',' << T << '}';
103e5dd7070Spatrick }
104e5dd7070Spatrick
anchor()105e5dd7070Spatrick void SymbolData::anchor() {}
106e5dd7070Spatrick
dumpToStream(raw_ostream & os) const107e5dd7070Spatrick void SymbolRegionValue::dumpToStream(raw_ostream &os) const {
108*12c85518Srobert os << getKindStr() << getSymbolID() << '<' << getType() << ' ' << R << '>';
109e5dd7070Spatrick }
110e5dd7070Spatrick
operator ==(const symbol_iterator & X) const111e5dd7070Spatrick bool SymExpr::symbol_iterator::operator==(const symbol_iterator &X) const {
112e5dd7070Spatrick return itr == X.itr;
113e5dd7070Spatrick }
114e5dd7070Spatrick
operator !=(const symbol_iterator & X) const115e5dd7070Spatrick bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const {
116e5dd7070Spatrick return itr != X.itr;
117e5dd7070Spatrick }
118e5dd7070Spatrick
symbol_iterator(const SymExpr * SE)119e5dd7070Spatrick SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
120e5dd7070Spatrick itr.push_back(SE);
121e5dd7070Spatrick }
122e5dd7070Spatrick
operator ++()123e5dd7070Spatrick SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
124e5dd7070Spatrick assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
125e5dd7070Spatrick expand();
126e5dd7070Spatrick return *this;
127e5dd7070Spatrick }
128e5dd7070Spatrick
operator *()129e5dd7070Spatrick SymbolRef SymExpr::symbol_iterator::operator*() {
130e5dd7070Spatrick assert(!itr.empty() && "attempting to dereference an 'end' iterator");
131e5dd7070Spatrick return itr.back();
132e5dd7070Spatrick }
133e5dd7070Spatrick
expand()134e5dd7070Spatrick void SymExpr::symbol_iterator::expand() {
135e5dd7070Spatrick const SymExpr *SE = itr.pop_back_val();
136e5dd7070Spatrick
137e5dd7070Spatrick switch (SE->getKind()) {
138e5dd7070Spatrick case SymExpr::SymbolRegionValueKind:
139e5dd7070Spatrick case SymExpr::SymbolConjuredKind:
140e5dd7070Spatrick case SymExpr::SymbolDerivedKind:
141e5dd7070Spatrick case SymExpr::SymbolExtentKind:
142e5dd7070Spatrick case SymExpr::SymbolMetadataKind:
143e5dd7070Spatrick return;
144e5dd7070Spatrick case SymExpr::SymbolCastKind:
145e5dd7070Spatrick itr.push_back(cast<SymbolCast>(SE)->getOperand());
146e5dd7070Spatrick return;
147*12c85518Srobert case SymExpr::UnarySymExprKind:
148*12c85518Srobert itr.push_back(cast<UnarySymExpr>(SE)->getOperand());
149*12c85518Srobert return;
150e5dd7070Spatrick case SymExpr::SymIntExprKind:
151e5dd7070Spatrick itr.push_back(cast<SymIntExpr>(SE)->getLHS());
152e5dd7070Spatrick return;
153e5dd7070Spatrick case SymExpr::IntSymExprKind:
154e5dd7070Spatrick itr.push_back(cast<IntSymExpr>(SE)->getRHS());
155e5dd7070Spatrick return;
156e5dd7070Spatrick case SymExpr::SymSymExprKind: {
157e5dd7070Spatrick const auto *x = cast<SymSymExpr>(SE);
158e5dd7070Spatrick itr.push_back(x->getLHS());
159e5dd7070Spatrick itr.push_back(x->getRHS());
160e5dd7070Spatrick return;
161e5dd7070Spatrick }
162e5dd7070Spatrick }
163e5dd7070Spatrick llvm_unreachable("unhandled expansion case");
164e5dd7070Spatrick }
165e5dd7070Spatrick
166e5dd7070Spatrick const SymbolRegionValue*
getRegionValueSymbol(const TypedValueRegion * R)167e5dd7070Spatrick SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
168e5dd7070Spatrick llvm::FoldingSetNodeID profile;
169e5dd7070Spatrick SymbolRegionValue::Profile(profile, R);
170e5dd7070Spatrick void *InsertPos;
171e5dd7070Spatrick SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
172e5dd7070Spatrick if (!SD) {
173e5dd7070Spatrick SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
174e5dd7070Spatrick new (SD) SymbolRegionValue(SymbolCounter, R);
175e5dd7070Spatrick DataSet.InsertNode(SD, InsertPos);
176e5dd7070Spatrick ++SymbolCounter;
177e5dd7070Spatrick }
178e5dd7070Spatrick
179e5dd7070Spatrick return cast<SymbolRegionValue>(SD);
180e5dd7070Spatrick }
181e5dd7070Spatrick
conjureSymbol(const Stmt * E,const LocationContext * LCtx,QualType T,unsigned Count,const void * SymbolTag)182e5dd7070Spatrick const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E,
183e5dd7070Spatrick const LocationContext *LCtx,
184e5dd7070Spatrick QualType T,
185e5dd7070Spatrick unsigned Count,
186e5dd7070Spatrick const void *SymbolTag) {
187e5dd7070Spatrick llvm::FoldingSetNodeID profile;
188e5dd7070Spatrick SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag);
189e5dd7070Spatrick void *InsertPos;
190e5dd7070Spatrick SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
191e5dd7070Spatrick if (!SD) {
192e5dd7070Spatrick SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
193e5dd7070Spatrick new (SD) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag);
194e5dd7070Spatrick DataSet.InsertNode(SD, InsertPos);
195e5dd7070Spatrick ++SymbolCounter;
196e5dd7070Spatrick }
197e5dd7070Spatrick
198e5dd7070Spatrick return cast<SymbolConjured>(SD);
199e5dd7070Spatrick }
200e5dd7070Spatrick
201e5dd7070Spatrick const SymbolDerived*
getDerivedSymbol(SymbolRef parentSymbol,const TypedValueRegion * R)202e5dd7070Spatrick SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
203e5dd7070Spatrick const TypedValueRegion *R) {
204e5dd7070Spatrick llvm::FoldingSetNodeID profile;
205e5dd7070Spatrick SymbolDerived::Profile(profile, parentSymbol, R);
206e5dd7070Spatrick void *InsertPos;
207e5dd7070Spatrick SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
208e5dd7070Spatrick if (!SD) {
209e5dd7070Spatrick SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
210e5dd7070Spatrick new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
211e5dd7070Spatrick DataSet.InsertNode(SD, InsertPos);
212e5dd7070Spatrick ++SymbolCounter;
213e5dd7070Spatrick }
214e5dd7070Spatrick
215e5dd7070Spatrick return cast<SymbolDerived>(SD);
216e5dd7070Spatrick }
217e5dd7070Spatrick
218e5dd7070Spatrick const SymbolExtent*
getExtentSymbol(const SubRegion * R)219e5dd7070Spatrick SymbolManager::getExtentSymbol(const SubRegion *R) {
220e5dd7070Spatrick llvm::FoldingSetNodeID profile;
221e5dd7070Spatrick SymbolExtent::Profile(profile, R);
222e5dd7070Spatrick void *InsertPos;
223e5dd7070Spatrick SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
224e5dd7070Spatrick if (!SD) {
225e5dd7070Spatrick SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
226e5dd7070Spatrick new (SD) SymbolExtent(SymbolCounter, R);
227e5dd7070Spatrick DataSet.InsertNode(SD, InsertPos);
228e5dd7070Spatrick ++SymbolCounter;
229e5dd7070Spatrick }
230e5dd7070Spatrick
231e5dd7070Spatrick return cast<SymbolExtent>(SD);
232e5dd7070Spatrick }
233e5dd7070Spatrick
234e5dd7070Spatrick const SymbolMetadata *
getMetadataSymbol(const MemRegion * R,const Stmt * S,QualType T,const LocationContext * LCtx,unsigned Count,const void * SymbolTag)235e5dd7070Spatrick SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
236e5dd7070Spatrick const LocationContext *LCtx,
237e5dd7070Spatrick unsigned Count, const void *SymbolTag) {
238e5dd7070Spatrick llvm::FoldingSetNodeID profile;
239e5dd7070Spatrick SymbolMetadata::Profile(profile, R, S, T, LCtx, Count, SymbolTag);
240e5dd7070Spatrick void *InsertPos;
241e5dd7070Spatrick SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
242e5dd7070Spatrick if (!SD) {
243e5dd7070Spatrick SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
244e5dd7070Spatrick new (SD) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag);
245e5dd7070Spatrick DataSet.InsertNode(SD, InsertPos);
246e5dd7070Spatrick ++SymbolCounter;
247e5dd7070Spatrick }
248e5dd7070Spatrick
249e5dd7070Spatrick return cast<SymbolMetadata>(SD);
250e5dd7070Spatrick }
251e5dd7070Spatrick
252e5dd7070Spatrick const SymbolCast*
getCastSymbol(const SymExpr * Op,QualType From,QualType To)253e5dd7070Spatrick SymbolManager::getCastSymbol(const SymExpr *Op,
254e5dd7070Spatrick QualType From, QualType To) {
255e5dd7070Spatrick llvm::FoldingSetNodeID ID;
256e5dd7070Spatrick SymbolCast::Profile(ID, Op, From, To);
257e5dd7070Spatrick void *InsertPos;
258e5dd7070Spatrick SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
259e5dd7070Spatrick if (!data) {
260e5dd7070Spatrick data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>();
261e5dd7070Spatrick new (data) SymbolCast(Op, From, To);
262e5dd7070Spatrick DataSet.InsertNode(data, InsertPos);
263e5dd7070Spatrick }
264e5dd7070Spatrick
265e5dd7070Spatrick return cast<SymbolCast>(data);
266e5dd7070Spatrick }
267e5dd7070Spatrick
getSymIntExpr(const SymExpr * lhs,BinaryOperator::Opcode op,const llvm::APSInt & v,QualType t)268e5dd7070Spatrick const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
269e5dd7070Spatrick BinaryOperator::Opcode op,
270e5dd7070Spatrick const llvm::APSInt& v,
271e5dd7070Spatrick QualType t) {
272e5dd7070Spatrick llvm::FoldingSetNodeID ID;
273e5dd7070Spatrick SymIntExpr::Profile(ID, lhs, op, v, t);
274e5dd7070Spatrick void *InsertPos;
275e5dd7070Spatrick SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
276e5dd7070Spatrick
277e5dd7070Spatrick if (!data) {
278e5dd7070Spatrick data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
279e5dd7070Spatrick new (data) SymIntExpr(lhs, op, v, t);
280e5dd7070Spatrick DataSet.InsertNode(data, InsertPos);
281e5dd7070Spatrick }
282e5dd7070Spatrick
283e5dd7070Spatrick return cast<SymIntExpr>(data);
284e5dd7070Spatrick }
285e5dd7070Spatrick
getIntSymExpr(const llvm::APSInt & lhs,BinaryOperator::Opcode op,const SymExpr * rhs,QualType t)286e5dd7070Spatrick const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs,
287e5dd7070Spatrick BinaryOperator::Opcode op,
288e5dd7070Spatrick const SymExpr *rhs,
289e5dd7070Spatrick QualType t) {
290e5dd7070Spatrick llvm::FoldingSetNodeID ID;
291e5dd7070Spatrick IntSymExpr::Profile(ID, lhs, op, rhs, t);
292e5dd7070Spatrick void *InsertPos;
293e5dd7070Spatrick SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
294e5dd7070Spatrick
295e5dd7070Spatrick if (!data) {
296e5dd7070Spatrick data = (IntSymExpr*) BPAlloc.Allocate<IntSymExpr>();
297e5dd7070Spatrick new (data) IntSymExpr(lhs, op, rhs, t);
298e5dd7070Spatrick DataSet.InsertNode(data, InsertPos);
299e5dd7070Spatrick }
300e5dd7070Spatrick
301e5dd7070Spatrick return cast<IntSymExpr>(data);
302e5dd7070Spatrick }
303e5dd7070Spatrick
getSymSymExpr(const SymExpr * lhs,BinaryOperator::Opcode op,const SymExpr * rhs,QualType t)304e5dd7070Spatrick const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
305e5dd7070Spatrick BinaryOperator::Opcode op,
306e5dd7070Spatrick const SymExpr *rhs,
307e5dd7070Spatrick QualType t) {
308e5dd7070Spatrick llvm::FoldingSetNodeID ID;
309e5dd7070Spatrick SymSymExpr::Profile(ID, lhs, op, rhs, t);
310e5dd7070Spatrick void *InsertPos;
311e5dd7070Spatrick SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
312e5dd7070Spatrick
313e5dd7070Spatrick if (!data) {
314e5dd7070Spatrick data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
315e5dd7070Spatrick new (data) SymSymExpr(lhs, op, rhs, t);
316e5dd7070Spatrick DataSet.InsertNode(data, InsertPos);
317e5dd7070Spatrick }
318e5dd7070Spatrick
319e5dd7070Spatrick return cast<SymSymExpr>(data);
320e5dd7070Spatrick }
321e5dd7070Spatrick
getUnarySymExpr(const SymExpr * Operand,UnaryOperator::Opcode Opc,QualType T)322*12c85518Srobert const UnarySymExpr *SymbolManager::getUnarySymExpr(const SymExpr *Operand,
323*12c85518Srobert UnaryOperator::Opcode Opc,
324*12c85518Srobert QualType T) {
325*12c85518Srobert llvm::FoldingSetNodeID ID;
326*12c85518Srobert UnarySymExpr::Profile(ID, Operand, Opc, T);
327*12c85518Srobert void *InsertPos;
328*12c85518Srobert SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
329*12c85518Srobert if (!data) {
330*12c85518Srobert data = (UnarySymExpr *)BPAlloc.Allocate<UnarySymExpr>();
331*12c85518Srobert new (data) UnarySymExpr(Operand, Opc, T);
332*12c85518Srobert DataSet.InsertNode(data, InsertPos);
333*12c85518Srobert }
334*12c85518Srobert
335*12c85518Srobert return cast<UnarySymExpr>(data);
336*12c85518Srobert }
337*12c85518Srobert
getType() const338e5dd7070Spatrick QualType SymbolConjured::getType() const {
339e5dd7070Spatrick return T;
340e5dd7070Spatrick }
341e5dd7070Spatrick
getType() const342e5dd7070Spatrick QualType SymbolDerived::getType() const {
343e5dd7070Spatrick return R->getValueType();
344e5dd7070Spatrick }
345e5dd7070Spatrick
getType() const346e5dd7070Spatrick QualType SymbolExtent::getType() const {
347ec727ea7Spatrick ASTContext &Ctx = R->getMemRegionManager().getContext();
348e5dd7070Spatrick return Ctx.getSizeType();
349e5dd7070Spatrick }
350e5dd7070Spatrick
getType() const351e5dd7070Spatrick QualType SymbolMetadata::getType() const {
352e5dd7070Spatrick return T;
353e5dd7070Spatrick }
354e5dd7070Spatrick
getType() const355e5dd7070Spatrick QualType SymbolRegionValue::getType() const {
356e5dd7070Spatrick return R->getValueType();
357e5dd7070Spatrick }
358e5dd7070Spatrick
canSymbolicate(QualType T)359e5dd7070Spatrick bool SymbolManager::canSymbolicate(QualType T) {
360e5dd7070Spatrick T = T.getCanonicalType();
361e5dd7070Spatrick
362e5dd7070Spatrick if (Loc::isLocType(T))
363e5dd7070Spatrick return true;
364e5dd7070Spatrick
365e5dd7070Spatrick if (T->isIntegralOrEnumerationType())
366e5dd7070Spatrick return true;
367e5dd7070Spatrick
368e5dd7070Spatrick if (T->isRecordType() && !T->isUnionType())
369e5dd7070Spatrick return true;
370e5dd7070Spatrick
371e5dd7070Spatrick return false;
372e5dd7070Spatrick }
373e5dd7070Spatrick
addSymbolDependency(const SymbolRef Primary,const SymbolRef Dependent)374e5dd7070Spatrick void SymbolManager::addSymbolDependency(const SymbolRef Primary,
375e5dd7070Spatrick const SymbolRef Dependent) {
376ec727ea7Spatrick auto &dependencies = SymbolDependencies[Primary];
377ec727ea7Spatrick if (!dependencies) {
378ec727ea7Spatrick dependencies = std::make_unique<SymbolRefSmallVectorTy>();
379e5dd7070Spatrick }
380e5dd7070Spatrick dependencies->push_back(Dependent);
381e5dd7070Spatrick }
382e5dd7070Spatrick
getDependentSymbols(const SymbolRef Primary)383e5dd7070Spatrick const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols(
384e5dd7070Spatrick const SymbolRef Primary) {
385e5dd7070Spatrick SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary);
386e5dd7070Spatrick if (I == SymbolDependencies.end())
387e5dd7070Spatrick return nullptr;
388ec727ea7Spatrick return I->second.get();
389e5dd7070Spatrick }
390e5dd7070Spatrick
markDependentsLive(SymbolRef sym)391e5dd7070Spatrick void SymbolReaper::markDependentsLive(SymbolRef sym) {
392e5dd7070Spatrick // Do not mark dependents more then once.
393e5dd7070Spatrick SymbolMapTy::iterator LI = TheLiving.find(sym);
394e5dd7070Spatrick assert(LI != TheLiving.end() && "The primary symbol is not live.");
395e5dd7070Spatrick if (LI->second == HaveMarkedDependents)
396e5dd7070Spatrick return;
397e5dd7070Spatrick LI->second = HaveMarkedDependents;
398e5dd7070Spatrick
399e5dd7070Spatrick if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) {
400e5dd7070Spatrick for (const auto I : *Deps) {
401e5dd7070Spatrick if (TheLiving.find(I) != TheLiving.end())
402e5dd7070Spatrick continue;
403e5dd7070Spatrick markLive(I);
404e5dd7070Spatrick }
405e5dd7070Spatrick }
406e5dd7070Spatrick }
407e5dd7070Spatrick
markLive(SymbolRef sym)408e5dd7070Spatrick void SymbolReaper::markLive(SymbolRef sym) {
409e5dd7070Spatrick TheLiving[sym] = NotProcessed;
410e5dd7070Spatrick markDependentsLive(sym);
411e5dd7070Spatrick }
412e5dd7070Spatrick
markLive(const MemRegion * region)413e5dd7070Spatrick void SymbolReaper::markLive(const MemRegion *region) {
414*12c85518Srobert LiveRegionRoots.insert(region->getBaseRegion());
415e5dd7070Spatrick markElementIndicesLive(region);
416e5dd7070Spatrick }
417e5dd7070Spatrick
markLazilyCopied(const clang::ento::MemRegion * region)418*12c85518Srobert void SymbolReaper::markLazilyCopied(const clang::ento::MemRegion *region) {
419*12c85518Srobert LazilyCopiedRegionRoots.insert(region->getBaseRegion());
420*12c85518Srobert }
421*12c85518Srobert
markElementIndicesLive(const MemRegion * region)422e5dd7070Spatrick void SymbolReaper::markElementIndicesLive(const MemRegion *region) {
423e5dd7070Spatrick for (auto SR = dyn_cast<SubRegion>(region); SR;
424e5dd7070Spatrick SR = dyn_cast<SubRegion>(SR->getSuperRegion())) {
425e5dd7070Spatrick if (const auto ER = dyn_cast<ElementRegion>(SR)) {
426e5dd7070Spatrick SVal Idx = ER->getIndex();
427e5dd7070Spatrick for (auto SI = Idx.symbol_begin(), SE = Idx.symbol_end(); SI != SE; ++SI)
428e5dd7070Spatrick markLive(*SI);
429e5dd7070Spatrick }
430e5dd7070Spatrick }
431e5dd7070Spatrick }
432e5dd7070Spatrick
markInUse(SymbolRef sym)433e5dd7070Spatrick void SymbolReaper::markInUse(SymbolRef sym) {
434e5dd7070Spatrick if (isa<SymbolMetadata>(sym))
435e5dd7070Spatrick MetadataInUse.insert(sym);
436e5dd7070Spatrick }
437e5dd7070Spatrick
isLiveRegion(const MemRegion * MR)438e5dd7070Spatrick bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
439e5dd7070Spatrick // TODO: For now, liveness of a memory region is equivalent to liveness of its
440e5dd7070Spatrick // base region. In fact we can do a bit better: say, if a particular FieldDecl
441e5dd7070Spatrick // is not used later in the path, we can diagnose a leak of a value within
442e5dd7070Spatrick // that field earlier than, say, the variable that contains the field dies.
443e5dd7070Spatrick MR = MR->getBaseRegion();
444*12c85518Srobert if (LiveRegionRoots.count(MR))
445e5dd7070Spatrick return true;
446e5dd7070Spatrick
447e5dd7070Spatrick if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
448e5dd7070Spatrick return isLive(SR->getSymbol());
449e5dd7070Spatrick
450e5dd7070Spatrick if (const auto *VR = dyn_cast<VarRegion>(MR))
451e5dd7070Spatrick return isLive(VR, true);
452e5dd7070Spatrick
453e5dd7070Spatrick // FIXME: This is a gross over-approximation. What we really need is a way to
454e5dd7070Spatrick // tell if anything still refers to this region. Unlike SymbolicRegions,
455e5dd7070Spatrick // AllocaRegions don't have associated symbols, though, so we don't actually
456e5dd7070Spatrick // have a way to track their liveness.
457*12c85518Srobert return isa<AllocaRegion, CXXThisRegion, MemSpaceRegion, CodeTextRegion>(MR);
458*12c85518Srobert }
459e5dd7070Spatrick
isLazilyCopiedRegion(const MemRegion * MR) const460*12c85518Srobert bool SymbolReaper::isLazilyCopiedRegion(const MemRegion *MR) const {
461*12c85518Srobert // TODO: See comment in isLiveRegion.
462*12c85518Srobert return LazilyCopiedRegionRoots.count(MR->getBaseRegion());
463*12c85518Srobert }
464e5dd7070Spatrick
isReadableRegion(const MemRegion * MR)465*12c85518Srobert bool SymbolReaper::isReadableRegion(const MemRegion *MR) {
466*12c85518Srobert return isLiveRegion(MR) || isLazilyCopiedRegion(MR);
467e5dd7070Spatrick }
468e5dd7070Spatrick
isLive(SymbolRef sym)469e5dd7070Spatrick bool SymbolReaper::isLive(SymbolRef sym) {
470e5dd7070Spatrick if (TheLiving.count(sym)) {
471e5dd7070Spatrick markDependentsLive(sym);
472e5dd7070Spatrick return true;
473e5dd7070Spatrick }
474e5dd7070Spatrick
475e5dd7070Spatrick bool KnownLive;
476e5dd7070Spatrick
477e5dd7070Spatrick switch (sym->getKind()) {
478e5dd7070Spatrick case SymExpr::SymbolRegionValueKind:
479*12c85518Srobert KnownLive = isReadableRegion(cast<SymbolRegionValue>(sym)->getRegion());
480e5dd7070Spatrick break;
481e5dd7070Spatrick case SymExpr::SymbolConjuredKind:
482e5dd7070Spatrick KnownLive = false;
483e5dd7070Spatrick break;
484e5dd7070Spatrick case SymExpr::SymbolDerivedKind:
485e5dd7070Spatrick KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol());
486e5dd7070Spatrick break;
487e5dd7070Spatrick case SymExpr::SymbolExtentKind:
488e5dd7070Spatrick KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion());
489e5dd7070Spatrick break;
490e5dd7070Spatrick case SymExpr::SymbolMetadataKind:
491e5dd7070Spatrick KnownLive = MetadataInUse.count(sym) &&
492e5dd7070Spatrick isLiveRegion(cast<SymbolMetadata>(sym)->getRegion());
493e5dd7070Spatrick if (KnownLive)
494e5dd7070Spatrick MetadataInUse.erase(sym);
495e5dd7070Spatrick break;
496e5dd7070Spatrick case SymExpr::SymIntExprKind:
497e5dd7070Spatrick KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS());
498e5dd7070Spatrick break;
499e5dd7070Spatrick case SymExpr::IntSymExprKind:
500e5dd7070Spatrick KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS());
501e5dd7070Spatrick break;
502e5dd7070Spatrick case SymExpr::SymSymExprKind:
503e5dd7070Spatrick KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) &&
504e5dd7070Spatrick isLive(cast<SymSymExpr>(sym)->getRHS());
505e5dd7070Spatrick break;
506e5dd7070Spatrick case SymExpr::SymbolCastKind:
507e5dd7070Spatrick KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
508e5dd7070Spatrick break;
509*12c85518Srobert case SymExpr::UnarySymExprKind:
510*12c85518Srobert KnownLive = isLive(cast<UnarySymExpr>(sym)->getOperand());
511*12c85518Srobert break;
512e5dd7070Spatrick }
513e5dd7070Spatrick
514e5dd7070Spatrick if (KnownLive)
515e5dd7070Spatrick markLive(sym);
516e5dd7070Spatrick
517e5dd7070Spatrick return KnownLive;
518e5dd7070Spatrick }
519e5dd7070Spatrick
520e5dd7070Spatrick bool
isLive(const Expr * ExprVal,const LocationContext * ELCtx) const521a9ac8606Spatrick SymbolReaper::isLive(const Expr *ExprVal, const LocationContext *ELCtx) const {
522e5dd7070Spatrick if (LCtx == nullptr)
523e5dd7070Spatrick return false;
524e5dd7070Spatrick
525e5dd7070Spatrick if (LCtx != ELCtx) {
526e5dd7070Spatrick // If the reaper's location context is a parent of the expression's
527e5dd7070Spatrick // location context, then the expression value is now "out of scope".
528e5dd7070Spatrick if (LCtx->isParentOf(ELCtx))
529e5dd7070Spatrick return false;
530e5dd7070Spatrick return true;
531e5dd7070Spatrick }
532e5dd7070Spatrick
533a9ac8606Spatrick // If no statement is provided, everything in this and parent contexts is
534a9ac8606Spatrick // live.
535e5dd7070Spatrick if (!Loc)
536e5dd7070Spatrick return true;
537e5dd7070Spatrick
538e5dd7070Spatrick return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal);
539e5dd7070Spatrick }
540e5dd7070Spatrick
isLive(const VarRegion * VR,bool includeStoreBindings) const541e5dd7070Spatrick bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
542e5dd7070Spatrick const StackFrameContext *VarContext = VR->getStackFrame();
543e5dd7070Spatrick
544e5dd7070Spatrick if (!VarContext)
545e5dd7070Spatrick return true;
546e5dd7070Spatrick
547e5dd7070Spatrick if (!LCtx)
548e5dd7070Spatrick return false;
549e5dd7070Spatrick const StackFrameContext *CurrentContext = LCtx->getStackFrame();
550e5dd7070Spatrick
551e5dd7070Spatrick if (VarContext == CurrentContext) {
552e5dd7070Spatrick // If no statement is provided, everything is live.
553e5dd7070Spatrick if (!Loc)
554e5dd7070Spatrick return true;
555e5dd7070Spatrick
556ec727ea7Spatrick // Anonymous parameters of an inheriting constructor are live for the entire
557ec727ea7Spatrick // duration of the constructor.
558ec727ea7Spatrick if (isa<CXXInheritedCtorInitExpr>(Loc))
559ec727ea7Spatrick return true;
560ec727ea7Spatrick
561e5dd7070Spatrick if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl()))
562e5dd7070Spatrick return true;
563e5dd7070Spatrick
564e5dd7070Spatrick if (!includeStoreBindings)
565e5dd7070Spatrick return false;
566e5dd7070Spatrick
567e5dd7070Spatrick unsigned &cachedQuery =
568e5dd7070Spatrick const_cast<SymbolReaper *>(this)->includedRegionCache[VR];
569e5dd7070Spatrick
570e5dd7070Spatrick if (cachedQuery) {
571e5dd7070Spatrick return cachedQuery == 1;
572e5dd7070Spatrick }
573e5dd7070Spatrick
574e5dd7070Spatrick // Query the store to see if the region occurs in any live bindings.
575e5dd7070Spatrick if (Store store = reapedStore.getStore()) {
576e5dd7070Spatrick bool hasRegion =
577e5dd7070Spatrick reapedStore.getStoreManager().includedInBindings(store, VR);
578e5dd7070Spatrick cachedQuery = hasRegion ? 1 : 2;
579e5dd7070Spatrick return hasRegion;
580e5dd7070Spatrick }
581e5dd7070Spatrick
582e5dd7070Spatrick return false;
583e5dd7070Spatrick }
584e5dd7070Spatrick
585e5dd7070Spatrick return VarContext->isParentOf(CurrentContext);
586e5dd7070Spatrick }
587