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
= (SymExpr
*) BPAlloc
.Allocate
<SymbolRegionValue
>();
174 new (SD
) SymbolRegionValue(SymbolCounter
, R
);
175 DataSet
.InsertNode(SD
, InsertPos
);
179 return cast
<SymbolRegionValue
>(SD
);
182 const SymbolConjured
* SymbolManager::conjureSymbol(const Stmt
*E
,
183 const LocationContext
*LCtx
,
186 const void *SymbolTag
) {
187 llvm::FoldingSetNodeID profile
;
188 SymbolConjured::Profile(profile
, E
, T
, Count
, LCtx
, SymbolTag
);
190 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
192 SD
= (SymExpr
*) BPAlloc
.Allocate
<SymbolConjured
>();
193 new (SD
) SymbolConjured(SymbolCounter
, E
, LCtx
, T
, Count
, SymbolTag
);
194 DataSet
.InsertNode(SD
, InsertPos
);
198 return cast
<SymbolConjured
>(SD
);
202 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol
,
203 const TypedValueRegion
*R
) {
204 llvm::FoldingSetNodeID profile
;
205 SymbolDerived::Profile(profile
, parentSymbol
, R
);
207 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
209 SD
= (SymExpr
*) BPAlloc
.Allocate
<SymbolDerived
>();
210 new (SD
) SymbolDerived(SymbolCounter
, parentSymbol
, R
);
211 DataSet
.InsertNode(SD
, InsertPos
);
215 return cast
<SymbolDerived
>(SD
);
219 SymbolManager::getExtentSymbol(const SubRegion
*R
) {
220 llvm::FoldingSetNodeID profile
;
221 SymbolExtent::Profile(profile
, R
);
223 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
225 SD
= (SymExpr
*) BPAlloc
.Allocate
<SymbolExtent
>();
226 new (SD
) SymbolExtent(SymbolCounter
, R
);
227 DataSet
.InsertNode(SD
, InsertPos
);
231 return cast
<SymbolExtent
>(SD
);
234 const SymbolMetadata
*
235 SymbolManager::getMetadataSymbol(const MemRegion
* R
, const Stmt
*S
, QualType T
,
236 const LocationContext
*LCtx
,
237 unsigned Count
, const void *SymbolTag
) {
238 llvm::FoldingSetNodeID profile
;
239 SymbolMetadata::Profile(profile
, R
, S
, T
, LCtx
, Count
, SymbolTag
);
241 SymExpr
*SD
= DataSet
.FindNodeOrInsertPos(profile
, InsertPos
);
243 SD
= (SymExpr
*) BPAlloc
.Allocate
<SymbolMetadata
>();
244 new (SD
) SymbolMetadata(SymbolCounter
, R
, S
, T
, LCtx
, Count
, SymbolTag
);
245 DataSet
.InsertNode(SD
, InsertPos
);
249 return cast
<SymbolMetadata
>(SD
);
253 SymbolManager::getCastSymbol(const SymExpr
*Op
,
254 QualType From
, QualType To
) {
255 llvm::FoldingSetNodeID ID
;
256 SymbolCast::Profile(ID
, Op
, From
, To
);
258 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
260 data
= (SymbolCast
*) BPAlloc
.Allocate
<SymbolCast
>();
261 new (data
) SymbolCast(Op
, From
, To
);
262 DataSet
.InsertNode(data
, InsertPos
);
265 return cast
<SymbolCast
>(data
);
268 const SymIntExpr
*SymbolManager::getSymIntExpr(const SymExpr
*lhs
,
269 BinaryOperator::Opcode op
,
270 const llvm::APSInt
& v
,
272 llvm::FoldingSetNodeID ID
;
273 SymIntExpr::Profile(ID
, lhs
, op
, v
, t
);
275 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
278 data
= (SymIntExpr
*) BPAlloc
.Allocate
<SymIntExpr
>();
279 new (data
) SymIntExpr(lhs
, op
, v
, t
);
280 DataSet
.InsertNode(data
, InsertPos
);
283 return cast
<SymIntExpr
>(data
);
286 const IntSymExpr
*SymbolManager::getIntSymExpr(const llvm::APSInt
& lhs
,
287 BinaryOperator::Opcode op
,
290 llvm::FoldingSetNodeID ID
;
291 IntSymExpr::Profile(ID
, lhs
, op
, rhs
, t
);
293 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
296 data
= (IntSymExpr
*) BPAlloc
.Allocate
<IntSymExpr
>();
297 new (data
) IntSymExpr(lhs
, op
, rhs
, t
);
298 DataSet
.InsertNode(data
, InsertPos
);
301 return cast
<IntSymExpr
>(data
);
304 const SymSymExpr
*SymbolManager::getSymSymExpr(const SymExpr
*lhs
,
305 BinaryOperator::Opcode op
,
308 llvm::FoldingSetNodeID ID
;
309 SymSymExpr::Profile(ID
, lhs
, op
, rhs
, t
);
311 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
314 data
= (SymSymExpr
*) BPAlloc
.Allocate
<SymSymExpr
>();
315 new (data
) SymSymExpr(lhs
, op
, rhs
, t
);
316 DataSet
.InsertNode(data
, InsertPos
);
319 return cast
<SymSymExpr
>(data
);
322 const UnarySymExpr
*SymbolManager::getUnarySymExpr(const SymExpr
*Operand
,
323 UnaryOperator::Opcode Opc
,
325 llvm::FoldingSetNodeID ID
;
326 UnarySymExpr::Profile(ID
, Operand
, Opc
, T
);
328 SymExpr
*data
= DataSet
.FindNodeOrInsertPos(ID
, InsertPos
);
330 data
= (UnarySymExpr
*)BPAlloc
.Allocate
<UnarySymExpr
>();
331 new (data
) UnarySymExpr(Operand
, Opc
, T
);
332 DataSet
.InsertNode(data
, InsertPos
);
335 return cast
<UnarySymExpr
>(data
);
338 QualType
SymbolConjured::getType() const {
342 QualType
SymbolDerived::getType() const {
343 return R
->getValueType();
346 QualType
SymbolExtent::getType() const {
347 ASTContext
&Ctx
= R
->getMemRegionManager().getContext();
348 return Ctx
.getSizeType();
351 QualType
SymbolMetadata::getType() const {
355 QualType
SymbolRegionValue::getType() const {
356 return R
->getValueType();
359 bool SymbolManager::canSymbolicate(QualType T
) {
360 T
= T
.getCanonicalType();
362 if (Loc::isLocType(T
))
365 if (T
->isIntegralOrEnumerationType())
368 if (T
->isRecordType() && !T
->isUnionType())
374 void SymbolManager::addSymbolDependency(const SymbolRef Primary
,
375 const SymbolRef Dependent
) {
376 auto &dependencies
= SymbolDependencies
[Primary
];
378 dependencies
= std::make_unique
<SymbolRefSmallVectorTy
>();
380 dependencies
->push_back(Dependent
);
383 const SymbolRefSmallVectorTy
*SymbolManager::getDependentSymbols(
384 const SymbolRef Primary
) {
385 SymbolDependTy::const_iterator I
= SymbolDependencies
.find(Primary
);
386 if (I
== SymbolDependencies
.end())
388 return I
->second
.get();
391 void SymbolReaper::markDependentsLive(SymbolRef sym
) {
392 // Do not mark dependents more then once.
393 SymbolMapTy::iterator LI
= TheLiving
.find(sym
);
394 assert(LI
!= TheLiving
.end() && "The primary symbol is not live.");
395 if (LI
->second
== HaveMarkedDependents
)
397 LI
->second
= HaveMarkedDependents
;
399 if (const SymbolRefSmallVectorTy
*Deps
= SymMgr
.getDependentSymbols(sym
)) {
400 for (const auto I
: *Deps
) {
401 if (TheLiving
.find(I
) != TheLiving
.end())
408 void SymbolReaper::markLive(SymbolRef sym
) {
409 TheLiving
[sym
] = NotProcessed
;
410 markDependentsLive(sym
);
413 void SymbolReaper::markLive(const MemRegion
*region
) {
414 LiveRegionRoots
.insert(region
->getBaseRegion());
415 markElementIndicesLive(region
);
418 void SymbolReaper::markLazilyCopied(const clang::ento::MemRegion
*region
) {
419 LazilyCopiedRegionRoots
.insert(region
->getBaseRegion());
422 void SymbolReaper::markElementIndicesLive(const MemRegion
*region
) {
423 for (auto SR
= dyn_cast
<SubRegion
>(region
); SR
;
424 SR
= dyn_cast
<SubRegion
>(SR
->getSuperRegion())) {
425 if (const auto ER
= dyn_cast
<ElementRegion
>(SR
)) {
426 SVal Idx
= ER
->getIndex();
427 for (auto SI
= Idx
.symbol_begin(), SE
= Idx
.symbol_end(); SI
!= SE
; ++SI
)
433 void SymbolReaper::markInUse(SymbolRef sym
) {
434 if (isa
<SymbolMetadata
>(sym
))
435 MetadataInUse
.insert(sym
);
438 bool SymbolReaper::isLiveRegion(const MemRegion
*MR
) {
439 // TODO: For now, liveness of a memory region is equivalent to liveness of its
440 // base region. In fact we can do a bit better: say, if a particular FieldDecl
441 // is not used later in the path, we can diagnose a leak of a value within
442 // that field earlier than, say, the variable that contains the field dies.
443 MR
= MR
->getBaseRegion();
444 if (LiveRegionRoots
.count(MR
))
447 if (const auto *SR
= dyn_cast
<SymbolicRegion
>(MR
))
448 return isLive(SR
->getSymbol());
450 if (const auto *VR
= dyn_cast
<VarRegion
>(MR
))
451 return isLive(VR
, true);
453 // FIXME: This is a gross over-approximation. What we really need is a way to
454 // tell if anything still refers to this region. Unlike SymbolicRegions,
455 // AllocaRegions don't have associated symbols, though, so we don't actually
456 // have a way to track their liveness.
457 return isa
<AllocaRegion
, CXXThisRegion
, MemSpaceRegion
, CodeTextRegion
>(MR
);
460 bool SymbolReaper::isLazilyCopiedRegion(const MemRegion
*MR
) const {
461 // TODO: See comment in isLiveRegion.
462 return LazilyCopiedRegionRoots
.count(MR
->getBaseRegion());
465 bool SymbolReaper::isReadableRegion(const MemRegion
*MR
) {
466 return isLiveRegion(MR
) || isLazilyCopiedRegion(MR
);
469 bool SymbolReaper::isLive(SymbolRef sym
) {
470 if (TheLiving
.count(sym
)) {
471 markDependentsLive(sym
);
477 switch (sym
->getKind()) {
478 case SymExpr::SymbolRegionValueKind
:
479 KnownLive
= isReadableRegion(cast
<SymbolRegionValue
>(sym
)->getRegion());
481 case SymExpr::SymbolConjuredKind
:
484 case SymExpr::SymbolDerivedKind
:
485 KnownLive
= isLive(cast
<SymbolDerived
>(sym
)->getParentSymbol());
487 case SymExpr::SymbolExtentKind
:
488 KnownLive
= isLiveRegion(cast
<SymbolExtent
>(sym
)->getRegion());
490 case SymExpr::SymbolMetadataKind
:
491 KnownLive
= MetadataInUse
.count(sym
) &&
492 isLiveRegion(cast
<SymbolMetadata
>(sym
)->getRegion());
494 MetadataInUse
.erase(sym
);
496 case SymExpr::SymIntExprKind
:
497 KnownLive
= isLive(cast
<SymIntExpr
>(sym
)->getLHS());
499 case SymExpr::IntSymExprKind
:
500 KnownLive
= isLive(cast
<IntSymExpr
>(sym
)->getRHS());
502 case SymExpr::SymSymExprKind
:
503 KnownLive
= isLive(cast
<SymSymExpr
>(sym
)->getLHS()) &&
504 isLive(cast
<SymSymExpr
>(sym
)->getRHS());
506 case SymExpr::SymbolCastKind
:
507 KnownLive
= isLive(cast
<SymbolCast
>(sym
)->getOperand());
509 case SymExpr::UnarySymExprKind
:
510 KnownLive
= isLive(cast
<UnarySymExpr
>(sym
)->getOperand());
521 SymbolReaper::isLive(const Expr
*ExprVal
, const LocationContext
*ELCtx
) const {
526 // If the reaper's location context is a parent of the expression's
527 // location context, then the expression value is now "out of scope".
528 if (LCtx
->isParentOf(ELCtx
))
533 // If no statement is provided, everything in this and parent contexts is
538 return LCtx
->getAnalysis
<RelaxedLiveVariables
>()->isLive(Loc
, ExprVal
);
541 bool SymbolReaper::isLive(const VarRegion
*VR
, bool includeStoreBindings
) const{
542 const StackFrameContext
*VarContext
= VR
->getStackFrame();
549 const StackFrameContext
*CurrentContext
= LCtx
->getStackFrame();
551 if (VarContext
== CurrentContext
) {
552 // If no statement is provided, everything is live.
556 // Anonymous parameters of an inheriting constructor are live for the entire
557 // duration of the constructor.
558 if (isa
<CXXInheritedCtorInitExpr
>(Loc
))
561 if (LCtx
->getAnalysis
<RelaxedLiveVariables
>()->isLive(Loc
, VR
->getDecl()))
564 if (!includeStoreBindings
)
567 unsigned &cachedQuery
=
568 const_cast<SymbolReaper
*>(this)->includedRegionCache
[VR
];
571 return cachedQuery
== 1;
574 // Query the store to see if the region occurs in any live bindings.
575 if (Store store
= reapedStore
.getStore()) {
577 reapedStore
.getStoreManager().includedInBindings(store
, VR
);
578 cachedQuery
= hasRegion
? 1 : 2;
585 return VarContext
->isParentOf(CurrentContext
);