1 //===- SymbolManager.h - Management of Symbolic Values --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file defines SymbolManager, a class that manages symbolic values
10 // created for use by ExprEngine and related classes.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Expr.h"
17 #include "clang/AST/StmtObjC.h"
18 #include "clang/Analysis/Analyses/LiveVariables.h"
19 #include "clang/Analysis/AnalysisDeclContext.h"
20 #include "clang/Basic/LLVM.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
24 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
25 #include "llvm/ADT/FoldingSet.h"
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/Support/Casting.h"
28 #include "llvm/Support/Compiler.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/raw_ostream.h"
33 using namespace clang
;
36 void SymExpr::anchor() {}
38 StringRef
SymbolConjured::getKindStr() const { return "conj_$"; }
39 StringRef
SymbolDerived::getKindStr() const { return "derived_$"; }
40 StringRef
SymbolExtent::getKindStr() const { return "extent_$"; }
41 StringRef
SymbolMetadata::getKindStr() const { return "meta_$"; }
42 StringRef
SymbolRegionValue::getKindStr() const { return "reg_$"; }
44 LLVM_DUMP_METHOD
void SymExpr::dump() const { dumpToStream(llvm::errs()); }
46 void BinarySymExpr::dumpToStreamImpl(raw_ostream
&OS
, const SymExpr
*Sym
) {
48 Sym
->dumpToStream(OS
);
52 void BinarySymExpr::dumpToStreamImpl(raw_ostream
&OS
,
53 const llvm::APSInt
&Value
) {
54 if (Value
.isUnsigned())
55 OS
<< Value
.getZExtValue();
57 OS
<< Value
.getSExtValue();
58 if (Value
.isUnsigned())
62 void BinarySymExpr::dumpToStreamImpl(raw_ostream
&OS
,
63 BinaryOperator::Opcode Op
) {
64 OS
<< ' ' << BinaryOperator::getOpcodeStr(Op
) << ' ';
67 void SymbolCast::dumpToStream(raw_ostream
&os
) const {
68 os
<< '(' << ToTy
<< ") (";
69 Operand
->dumpToStream(os
);
73 void UnarySymExpr::dumpToStream(raw_ostream
&os
) const {
74 os
<< UnaryOperator::getOpcodeStr(Op
);
75 bool Binary
= isa
<BinarySymExpr
>(Operand
);
78 Operand
->dumpToStream(os
);
83 void SymbolConjured::dumpToStream(raw_ostream
&os
) const {
84 os
<< getKindStr() << getSymbolID() << '{' << T
<< ", LC" << LCtx
->getID();
86 os
<< ", S" << S
->getID(LCtx
->getDecl()->getASTContext());
89 os
<< ", #" << Count
<< '}';
92 void SymbolDerived::dumpToStream(raw_ostream
&os
) const {
93 os
<< getKindStr() << getSymbolID() << '{' << getParentSymbol() << ','
94 << getRegion() << '}';
97 void SymbolExtent::dumpToStream(raw_ostream
&os
) const {
98 os
<< getKindStr() << getSymbolID() << '{' << getRegion() << '}';
101 void SymbolMetadata::dumpToStream(raw_ostream
&os
) const {
102 os
<< getKindStr() << getSymbolID() << '{' << getRegion() << ',' << T
<< '}';
105 void SymbolData::anchor() {}
107 void SymbolRegionValue::dumpToStream(raw_ostream
&os
) const {
108 os
<< getKindStr() << getSymbolID() << '<' << getType() << ' ' << R
<< '>';
111 bool SymExpr::symbol_iterator::operator==(const symbol_iterator
&X
) const {
115 bool SymExpr::symbol_iterator::operator!=(const symbol_iterator
&X
) const {
119 SymExpr::symbol_iterator::symbol_iterator(const SymExpr
*SE
) {
123 SymExpr::symbol_iterator
&SymExpr::symbol_iterator::operator++() {
124 assert(!itr
.empty() && "attempting to iterate on an 'end' iterator");
129 SymbolRef
SymExpr::symbol_iterator::operator*() {
130 assert(!itr
.empty() && "attempting to dereference an 'end' iterator");
134 void SymExpr::symbol_iterator::expand() {
135 const SymExpr
*SE
= itr
.pop_back_val();
137 switch (SE
->getKind()) {
138 case SymExpr::SymbolRegionValueKind
:
139 case SymExpr::SymbolConjuredKind
:
140 case SymExpr::SymbolDerivedKind
:
141 case SymExpr::SymbolExtentKind
:
142 case SymExpr::SymbolMetadataKind
:
144 case SymExpr::SymbolCastKind
:
145 itr
.push_back(cast
<SymbolCast
>(SE
)->getOperand());
147 case SymExpr::UnarySymExprKind
:
148 itr
.push_back(cast
<UnarySymExpr
>(SE
)->getOperand());
150 case SymExpr::SymIntExprKind
:
151 itr
.push_back(cast
<SymIntExpr
>(SE
)->getLHS());
153 case SymExpr::IntSymExprKind
:
154 itr
.push_back(cast
<IntSymExpr
>(SE
)->getRHS());
156 case SymExpr::SymSymExprKind
: {
157 const auto *x
= cast
<SymSymExpr
>(SE
);
158 itr
.push_back(x
->getLHS());
159 itr
.push_back(x
->getRHS());
163 llvm_unreachable("unhandled expansion case");
166 const SymbolRegionValue
*
167 SymbolManager::getRegionValueSymbol(const TypedValueRegion
* R
) {
168 llvm::FoldingSetNodeID profile
;
169 SymbolRegionValue::Profile(profile
, R
);
171 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
173 SD
= new (BPAlloc
) SymbolRegionValue(SymbolCounter
, R
);
174 DataSet
.InsertNode(SD
, InsertPos
);
178 return cast
<SymbolRegionValue
>(SD
);
181 const SymbolConjured
* SymbolManager::conjureSymbol(const Stmt
*E
,
182 const LocationContext
*LCtx
,
185 const void *SymbolTag
) {
186 llvm::FoldingSetNodeID profile
;
187 SymbolConjured::Profile(profile
, E
, T
, Count
, LCtx
, SymbolTag
);
189 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
191 SD
= new (BPAlloc
) SymbolConjured(SymbolCounter
, E
, LCtx
, T
, Count
, SymbolTag
);
192 DataSet
.InsertNode(SD
, InsertPos
);
196 return cast
<SymbolConjured
>(SD
);
200 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol
,
201 const TypedValueRegion
*R
) {
202 llvm::FoldingSetNodeID profile
;
203 SymbolDerived::Profile(profile
, parentSymbol
, R
);
205 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
207 SD
= new (BPAlloc
) SymbolDerived(SymbolCounter
, parentSymbol
, R
);
208 DataSet
.InsertNode(SD
, InsertPos
);
212 return cast
<SymbolDerived
>(SD
);
216 SymbolManager::getExtentSymbol(const SubRegion
*R
) {
217 llvm::FoldingSetNodeID profile
;
218 SymbolExtent::Profile(profile
, R
);
220 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
222 SD
= new (BPAlloc
) SymbolExtent(SymbolCounter
, R
);
223 DataSet
.InsertNode(SD
, InsertPos
);
227 return cast
<SymbolExtent
>(SD
);
230 const SymbolMetadata
*
231 SymbolManager::getMetadataSymbol(const MemRegion
* R
, const Stmt
*S
, QualType T
,
232 const LocationContext
*LCtx
,
233 unsigned Count
, const void *SymbolTag
) {
234 llvm::FoldingSetNodeID profile
;
235 SymbolMetadata::Profile(profile
, R
, S
, T
, LCtx
, Count
, SymbolTag
);
237 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
239 SD
= new (BPAlloc
) SymbolMetadata(SymbolCounter
, R
, S
, T
, LCtx
, Count
, SymbolTag
);
240 DataSet
.InsertNode(SD
, InsertPos
);
244 return cast
<SymbolMetadata
>(SD
);
248 SymbolManager::getCastSymbol(const SymExpr
*Op
,
249 QualType From
, QualType To
) {
250 llvm::FoldingSetNodeID ID
;
251 SymbolCast::Profile(ID
, Op
, From
, To
);
253 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
255 data
= new (BPAlloc
) SymbolCast(Op
, From
, To
);
256 DataSet
.InsertNode(data
, InsertPos
);
259 return cast
<SymbolCast
>(data
);
262 const SymIntExpr
*SymbolManager::getSymIntExpr(const SymExpr
*lhs
,
263 BinaryOperator::Opcode op
,
264 const llvm::APSInt
& v
,
266 llvm::FoldingSetNodeID ID
;
267 SymIntExpr::Profile(ID
, lhs
, op
, v
, t
);
269 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
272 data
= new (BPAlloc
) SymIntExpr(lhs
, op
, v
, t
);
273 DataSet
.InsertNode(data
, InsertPos
);
276 return cast
<SymIntExpr
>(data
);
279 const IntSymExpr
*SymbolManager::getIntSymExpr(const llvm::APSInt
& lhs
,
280 BinaryOperator::Opcode op
,
283 llvm::FoldingSetNodeID ID
;
284 IntSymExpr::Profile(ID
, lhs
, op
, rhs
, t
);
286 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
289 data
= new (BPAlloc
) IntSymExpr(lhs
, op
, rhs
, t
);
290 DataSet
.InsertNode(data
, InsertPos
);
293 return cast
<IntSymExpr
>(data
);
296 const SymSymExpr
*SymbolManager::getSymSymExpr(const SymExpr
*lhs
,
297 BinaryOperator::Opcode op
,
300 llvm::FoldingSetNodeID ID
;
301 SymSymExpr::Profile(ID
, lhs
, op
, rhs
, t
);
303 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
306 data
= new (BPAlloc
) SymSymExpr(lhs
, op
, rhs
, t
);
307 DataSet
.InsertNode(data
, InsertPos
);
310 return cast
<SymSymExpr
>(data
);
313 const UnarySymExpr
*SymbolManager::getUnarySymExpr(const SymExpr
*Operand
,
314 UnaryOperator::Opcode Opc
,
316 llvm::FoldingSetNodeID ID
;
317 UnarySymExpr::Profile(ID
, Operand
, Opc
, T
);
319 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
321 data
= new (BPAlloc
) UnarySymExpr(Operand
, Opc
, T
);
322 DataSet
.InsertNode(data
, InsertPos
);
325 return cast
<UnarySymExpr
>(data
);
328 QualType
SymbolConjured::getType() const {
332 QualType
SymbolDerived::getType() const {
333 return R
->getValueType();
336 QualType
SymbolExtent::getType() const {
337 ASTContext
&Ctx
= R
->getMemRegionManager().getContext();
338 return Ctx
.getSizeType();
341 QualType
SymbolMetadata::getType() const {
345 QualType
SymbolRegionValue::getType() const {
346 return R
->getValueType();
349 bool SymbolManager::canSymbolicate(QualType T
) {
350 T
= T
.getCanonicalType();
352 if (Loc::isLocType(T
))
355 if (T
->isIntegralOrEnumerationType())
358 if (T
->isRecordType() && !T
->isUnionType())
364 void SymbolManager::addSymbolDependency(const SymbolRef Primary
,
365 const SymbolRef Dependent
) {
366 auto &dependencies
= SymbolDependencies
[Primary
];
368 dependencies
= std::make_unique
<SymbolRefSmallVectorTy
>();
370 dependencies
->push_back(Dependent
);
373 const SymbolRefSmallVectorTy
*SymbolManager::getDependentSymbols(
374 const SymbolRef Primary
) {
375 SymbolDependTy::const_iterator I
= SymbolDependencies
.find(Primary
);
376 if (I
== SymbolDependencies
.end())
378 return I
->second
.get();
381 void SymbolReaper::markDependentsLive(SymbolRef sym
) {
382 // Do not mark dependents more then once.
383 SymbolMapTy::iterator LI
= TheLiving
.find(sym
);
384 assert(LI
!= TheLiving
.end() && "The primary symbol is not live.");
385 if (LI
->second
== HaveMarkedDependents
)
387 LI
->second
= HaveMarkedDependents
;
389 if (const SymbolRefSmallVectorTy
*Deps
= SymMgr
.getDependentSymbols(sym
)) {
390 for (const auto I
: *Deps
) {
391 if (TheLiving
.contains(I
))
398 void SymbolReaper::markLive(SymbolRef sym
) {
399 TheLiving
[sym
] = NotProcessed
;
400 markDependentsLive(sym
);
403 void SymbolReaper::markLive(const MemRegion
*region
) {
404 LiveRegionRoots
.insert(region
->getBaseRegion());
405 markElementIndicesLive(region
);
408 void SymbolReaper::markLazilyCopied(const clang::ento::MemRegion
*region
) {
409 LazilyCopiedRegionRoots
.insert(region
->getBaseRegion());
412 void SymbolReaper::markElementIndicesLive(const MemRegion
*region
) {
413 for (auto SR
= dyn_cast
<SubRegion
>(region
); SR
;
414 SR
= dyn_cast
<SubRegion
>(SR
->getSuperRegion())) {
415 if (const auto ER
= dyn_cast
<ElementRegion
>(SR
)) {
416 SVal Idx
= ER
->getIndex();
417 for (SymbolRef Sym
: Idx
.symbols())
423 void SymbolReaper::markInUse(SymbolRef sym
) {
424 if (isa
<SymbolMetadata
>(sym
))
425 MetadataInUse
.insert(sym
);
428 bool SymbolReaper::isLiveRegion(const MemRegion
*MR
) {
429 // TODO: For now, liveness of a memory region is equivalent to liveness of its
430 // base region. In fact we can do a bit better: say, if a particular FieldDecl
431 // is not used later in the path, we can diagnose a leak of a value within
432 // that field earlier than, say, the variable that contains the field dies.
433 MR
= MR
->getBaseRegion();
434 if (LiveRegionRoots
.count(MR
))
437 if (const auto *SR
= dyn_cast
<SymbolicRegion
>(MR
))
438 return isLive(SR
->getSymbol());
440 if (const auto *VR
= dyn_cast
<VarRegion
>(MR
))
441 return isLive(VR
, true);
443 // FIXME: This is a gross over-approximation. What we really need is a way to
444 // tell if anything still refers to this region. Unlike SymbolicRegions,
445 // AllocaRegions don't have associated symbols, though, so we don't actually
446 // have a way to track their liveness.
447 return isa
<AllocaRegion
, CXXThisRegion
, MemSpaceRegion
, CodeTextRegion
>(MR
);
450 bool SymbolReaper::isLazilyCopiedRegion(const MemRegion
*MR
) const {
451 // TODO: See comment in isLiveRegion.
452 return LazilyCopiedRegionRoots
.count(MR
->getBaseRegion());
455 bool SymbolReaper::isReadableRegion(const MemRegion
*MR
) {
456 return isLiveRegion(MR
) || isLazilyCopiedRegion(MR
);
459 bool SymbolReaper::isLive(SymbolRef sym
) {
460 if (TheLiving
.count(sym
)) {
461 markDependentsLive(sym
);
467 switch (sym
->getKind()) {
468 case SymExpr::SymbolRegionValueKind
:
469 KnownLive
= isReadableRegion(cast
<SymbolRegionValue
>(sym
)->getRegion());
471 case SymExpr::SymbolConjuredKind
:
474 case SymExpr::SymbolDerivedKind
:
475 KnownLive
= isLive(cast
<SymbolDerived
>(sym
)->getParentSymbol());
477 case SymExpr::SymbolExtentKind
:
478 KnownLive
= isLiveRegion(cast
<SymbolExtent
>(sym
)->getRegion());
480 case SymExpr::SymbolMetadataKind
:
481 KnownLive
= MetadataInUse
.count(sym
) &&
482 isLiveRegion(cast
<SymbolMetadata
>(sym
)->getRegion());
484 MetadataInUse
.erase(sym
);
486 case SymExpr::SymIntExprKind
:
487 KnownLive
= isLive(cast
<SymIntExpr
>(sym
)->getLHS());
489 case SymExpr::IntSymExprKind
:
490 KnownLive
= isLive(cast
<IntSymExpr
>(sym
)->getRHS());
492 case SymExpr::SymSymExprKind
:
493 KnownLive
= isLive(cast
<SymSymExpr
>(sym
)->getLHS()) &&
494 isLive(cast
<SymSymExpr
>(sym
)->getRHS());
496 case SymExpr::SymbolCastKind
:
497 KnownLive
= isLive(cast
<SymbolCast
>(sym
)->getOperand());
499 case SymExpr::UnarySymExprKind
:
500 KnownLive
= isLive(cast
<UnarySymExpr
>(sym
)->getOperand());
511 SymbolReaper::isLive(const Expr
*ExprVal
, const LocationContext
*ELCtx
) const {
516 // If the reaper's location context is a parent of the expression's
517 // location context, then the expression value is now "out of scope".
518 if (LCtx
->isParentOf(ELCtx
))
523 // If no statement is provided, everything in this and parent contexts is
528 return LCtx
->getAnalysis
<RelaxedLiveVariables
>()->isLive(Loc
, ExprVal
);
531 bool SymbolReaper::isLive(const VarRegion
*VR
, bool includeStoreBindings
) const{
532 const StackFrameContext
*VarContext
= VR
->getStackFrame();
539 const StackFrameContext
*CurrentContext
= LCtx
->getStackFrame();
541 if (VarContext
== CurrentContext
) {
542 // If no statement is provided, everything is live.
546 // Anonymous parameters of an inheriting constructor are live for the entire
547 // duration of the constructor.
548 if (isa
<CXXInheritedCtorInitExpr
>(Loc
))
551 if (LCtx
->getAnalysis
<RelaxedLiveVariables
>()->isLive(Loc
, VR
->getDecl()))
554 if (!includeStoreBindings
)
557 unsigned &cachedQuery
=
558 const_cast<SymbolReaper
*>(this)->includedRegionCache
[VR
];
561 return cachedQuery
== 1;
564 // Query the store to see if the region occurs in any live bindings.
565 if (Store store
= reapedStore
.getStore()) {
567 reapedStore
.getStoreManager().includedInBindings(store
, VR
);
568 cachedQuery
= hasRegion
? 1 : 2;
575 return VarContext
->isParentOf(CurrentContext
);