Skip to content

Commit 87b45cc

Browse files
committed
[Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured
Closes #57270. This PR changes the `Stmt *` field in `SymbolConjured` with `CFGBlock::ConstCFGElementRef`. The motivation is that, when conjuring a symbol, there might not always be a statement available, causing information to be lost for conjured symbols, whereas the CFGElementRef can always be provided at the callsite. Following the idea, this PR changes callsites of functions to create conjured symbols, and replaces them with appropriate `CFGElementRef`s.
1 parent 566c30e commit 87b45cc

38 files changed

+507
-400
lines changed

clang/include/clang/Analysis/CFG.h

+5
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,11 @@ class CFGBlock {
695695
void dump() const {
696696
dumpToStream(llvm::errs());
697697
}
698+
699+
void Profile(llvm::FoldingSetNodeID &ID) const {
700+
ID.AddPointer(Parent);
701+
ID.AddInteger(Index);
702+
}
698703
};
699704

700705
template <bool IsReverse, bool IsConst> class ElementRefIterator {

clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#include "clang/AST/DeclCXX.h"
2020
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
2121
#include "llvm/ADT/StringExtras.h"
22+
#include "llvm/ADT/StringRef.h"
23+
#include "llvm/Support/raw_ostream.h"
24+
#include <cctype>
2225

2326
namespace clang {
2427

@@ -29,6 +32,17 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
2932
ASTContext &ACtx;
3033
ProgramStateRef State;
3134

35+
std::string printCFGElementRef(CFGBlock::ConstCFGElementRef ElemRef) {
36+
std::string Str;
37+
llvm::raw_string_ostream OS(Str);
38+
ElemRef->dumpToStream(OS);
39+
// HACK: `CFGBlock::ConstCFGElementRef::dumpToStream` contains a new line
40+
// character in the end of the string, we don't want it so we remove it
41+
// here.
42+
llvm::StringRef StrRef(Str);
43+
return StrRef.rtrim().str();
44+
}
45+
3246
std::string printStmt(const Stmt *S) {
3347
std::string Str;
3448
llvm::raw_string_ostream OS(Str);
@@ -114,7 +128,8 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
114128

115129
std::string VisitSymbolConjured(const SymbolConjured *S) {
116130
return "symbol of type '" + S->getType().getAsString() +
117-
"' conjured at statement '" + printStmt(S->getStmt()) + "'";
131+
"' conjured at statement '" +
132+
printCFGElementRef(S->getCFGElementRef()) + "'";
118133
}
119134

120135
std::string VisitSymbolDerived(const SymbolDerived *S) {

clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h

+4
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ class CheckerContext {
151151
return Pred->getSVal(S);
152152
}
153153

154+
CFGBlock::ConstCFGElementRef getCFGElementRef() const {
155+
return Eng.getCFGElementRef();
156+
}
157+
154158
/// Returns true if the value of \p E is greater than or equal to \p
155159
/// Val under unsigned comparison.
156160
bool isGreaterOrEqual(const Expr *E, unsigned long long Val);

clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ namespace ento {
2727
/// by the loop body in any iteration.
2828
ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
2929
const LocationContext *LCtx,
30-
unsigned BlockCount, const Stmt *LoopStmt);
30+
unsigned BlockCount,
31+
CFGBlock::ConstCFGElementRef ElemRef);
3132

3233
} // end namespace ento
3334
} // end namespace clang

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h

+9-7
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ class ProgramState : public llvm::FoldingSetNode {
313313
/// be triggered by this event.
314314
///
315315
/// \param Regions the set of regions to be invalidated.
316-
/// \param E the expression that caused the invalidation.
316+
/// \param ElemRef \p CFGBlock::ConstCFGElementRef that caused the
317+
/// invalidation.
317318
/// \param BlockCount The number of times the current basic block has been
318319
/// visited.
319320
/// \param CausesPointerEscape the flag is set to true when the invalidation
@@ -325,16 +326,17 @@ class ProgramState : public llvm::FoldingSetNode {
325326
/// \param ITraits information about special handling for particular regions
326327
/// or symbols.
327328
[[nodiscard]] ProgramStateRef
328-
invalidateRegions(ArrayRef<const MemRegion *> Regions, const Stmt *S,
329-
unsigned BlockCount, const LocationContext *LCtx,
330-
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
329+
invalidateRegions(ArrayRef<const MemRegion *> Regions,
330+
CFGBlock::ConstCFGElementRef ElemRef, unsigned BlockCount,
331+
const LocationContext *LCtx, bool CausesPointerEscape,
332+
InvalidatedSymbols *IS = nullptr,
331333
const CallEvent *Call = nullptr,
332334
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
333335

334336
[[nodiscard]] ProgramStateRef
335-
invalidateRegions(ArrayRef<SVal> Values, const Stmt *S, unsigned BlockCount,
336-
const LocationContext *LCtx, bool CausesPointerEscape,
337-
InvalidatedSymbols *IS = nullptr,
337+
invalidateRegions(ArrayRef<SVal> Values, CFGBlock::ConstCFGElementRef ElemRef,
338+
unsigned BlockCount, const LocationContext *LCtx,
339+
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
338340
const CallEvent *Call = nullptr,
339341
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
340342

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h

+10-27
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/AST/Expr.h"
2020
#include "clang/AST/ExprObjC.h"
2121
#include "clang/AST/Type.h"
22+
#include "clang/Analysis/CFG.h"
2223
#include "clang/Basic/LLVM.h"
2324
#include "clang/Basic/LangOptions.h"
2425
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
@@ -171,19 +172,11 @@ class SValBuilder {
171172

172173
// Forwarding methods to SymbolManager.
173174

174-
const SymbolConjured* conjureSymbol(const Stmt *stmt,
175+
const SymbolConjured *conjureSymbol(CFGBlock::ConstCFGElementRef ElemRef,
175176
const LocationContext *LCtx,
176-
QualType type,
177-
unsigned visitCount,
177+
QualType type, unsigned visitCount,
178178
const void *symbolTag = nullptr) {
179-
return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
180-
}
181-
182-
const SymbolConjured* conjureSymbol(const Expr *expr,
183-
const LocationContext *LCtx,
184-
unsigned visitCount,
185-
const void *symbolTag = nullptr) {
186-
return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
179+
return SymMgr.conjureSymbol(ElemRef, LCtx, type, visitCount, symbolTag);
187180
}
188181

189182
/// Construct an SVal representing '0' for the specified type.
@@ -199,29 +192,19 @@ class SValBuilder {
199192
/// preserve the relation between related(or even equivalent) expressions, so
200193
/// conjured symbols should be used sparingly.
201194
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
202-
const Expr *expr,
195+
CFGBlock::ConstCFGElementRef elemRef,
203196
const LocationContext *LCtx,
204197
unsigned count);
205-
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S,
198+
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
199+
CFGBlock::ConstCFGElementRef elemRef,
206200
const LocationContext *LCtx,
207201
QualType type, unsigned count);
208-
DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
202+
DefinedOrUnknownSVal conjureSymbolVal(CFGBlock::ConstCFGElementRef elemRef,
209203
const LocationContext *LCtx,
210-
QualType type,
211-
unsigned visitCount);
204+
QualType type, unsigned visitCount);
212205

213206
/// Conjure a symbol representing heap allocated memory region.
214-
///
215-
/// Note, the expression should represent a location.
216-
DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
217-
const LocationContext *LCtx,
218-
unsigned Count);
219-
220-
/// Conjure a symbol representing heap allocated memory region.
221-
///
222-
/// Note, now, the expression *doesn't* need to represent a location.
223-
/// But the type need to!
224-
DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
207+
DefinedSVal getConjuredHeapSymbolVal(CFGBlock::ConstCFGElementRef elemRef,
225208
const LocationContext *LCtx,
226209
QualType type, unsigned Count);
227210

clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
1515

1616
#include "clang/AST/Type.h"
17+
#include "clang/Basic/LLVM.h"
1718
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
1819
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
1920
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
2021
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
2122
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
2223
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
23-
#include "clang/Basic/LLVM.h"
2424
#include "llvm/ADT/ArrayRef.h"
2525
#include "llvm/ADT/DenseSet.h"
2626
#include "llvm/ADT/SmallVector.h"
@@ -223,8 +223,9 @@ class StoreManager {
223223
///
224224
/// \param[in] store The initial store.
225225
/// \param[in] Values The values to invalidate.
226-
/// \param[in] S The current statement being evaluated. Used to conjure
227-
/// symbols to mark the values of invalidated regions.
226+
/// \param[in] ElemRef The current \p CFGBlock::ConstCFGElementRef being
227+
/// evaluated. Used to conjure symbols to mark the values of invalidated
228+
/// regions.
228229
/// \param[in] Count The current block count. Used to conjure
229230
/// symbols to mark the values of invalidated regions.
230231
/// \param[in] Call The call expression which will be used to determine which
@@ -241,8 +242,8 @@ class StoreManager {
241242
/// even if they do not currently have bindings. Pass \c NULL if this
242243
/// information will not be used.
243244
virtual StoreRef invalidateRegions(
244-
Store store, ArrayRef<SVal> Values, const Stmt *S, unsigned Count,
245-
const LocationContext *LCtx, const CallEvent *Call,
245+
Store store, ArrayRef<SVal> Values, CFGBlock::ConstCFGElementRef ElemRef,
246+
unsigned Count, const LocationContext *LCtx, const CallEvent *Call,
246247
InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits,
247248
InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0;
248249

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h

+53-23
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,64 @@ class SymbolRegionValue : public SymbolData {
8080
/// A symbol representing the result of an expression in the case when we do
8181
/// not know anything about what the expression is.
8282
class SymbolConjured : public SymbolData {
83-
const Stmt *S;
83+
CFGBlock::ConstCFGElementRef ElemRef;
8484
QualType T;
8585
unsigned Count;
8686
const LocationContext *LCtx;
8787
const void *SymbolTag;
8888

8989
friend class SymExprAllocator;
90-
SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
91-
QualType t, unsigned count, const void *symbolTag)
92-
: SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
93-
LCtx(lctx), SymbolTag(symbolTag) {
94-
// FIXME: 's' might be a nullptr if we're conducting invalidation
95-
// that was caused by a destructor call on a temporary object,
96-
// which has no statement associated with it.
97-
// Due to this, we might be creating the same invalidation symbol for
98-
// two different invalidation passes (for two different temporaries).
90+
SymbolConjured(SymbolID sym, CFGBlock::ConstCFGElementRef elemRef,
91+
const LocationContext *lctx, QualType t, unsigned count,
92+
const void *symbolTag)
93+
: SymbolData(SymbolConjuredKind, sym), ElemRef(elemRef), T(t),
94+
Count(count), LCtx(lctx), SymbolTag(symbolTag) {
9995
assert(lctx);
10096
assert(isValidTypeForSymbol(t));
10197
}
10298

10399
public:
104-
/// It might return null.
105-
const Stmt *getStmt() const { return S; }
100+
const CFGBlock::ConstCFGElementRef getCFGElementRef() const {
101+
return ElemRef;
102+
}
103+
104+
// It might return null.
105+
const Stmt *getStmt() const {
106+
switch (ElemRef->getKind()) {
107+
case CFGElement::Initializer:
108+
return ElemRef->castAs<CFGInitializer>().getInitializer()->getInit();
109+
case CFGElement::ScopeBegin:
110+
return ElemRef->castAs<CFGScopeBegin>().getTriggerStmt();
111+
case CFGElement::ScopeEnd:
112+
return ElemRef->castAs<CFGScopeEnd>().getTriggerStmt();
113+
case CFGElement::NewAllocator:
114+
return ElemRef->castAs<CFGNewAllocator>().getAllocatorExpr();
115+
case CFGElement::LifetimeEnds:
116+
return ElemRef->castAs<CFGLifetimeEnds>().getTriggerStmt();
117+
case CFGElement::LoopExit:
118+
return ElemRef->castAs<CFGLoopExit>().getLoopStmt();
119+
case CFGElement::Statement:
120+
return ElemRef->castAs<CFGStmt>().getStmt();
121+
case CFGElement::Constructor:
122+
return ElemRef->castAs<CFGConstructor>().getStmt();
123+
case CFGElement::CXXRecordTypedCall:
124+
return ElemRef->castAs<CFGCXXRecordTypedCall>().getStmt();
125+
case CFGElement::AutomaticObjectDtor:
126+
return ElemRef->castAs<CFGAutomaticObjDtor>().getTriggerStmt();
127+
case CFGElement::DeleteDtor:
128+
return ElemRef->castAs<CFGDeleteDtor>().getDeleteExpr();
129+
case CFGElement::BaseDtor:
130+
return nullptr;
131+
case CFGElement::MemberDtor:
132+
return nullptr;
133+
case CFGElement::TemporaryDtor:
134+
return ElemRef->castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
135+
case CFGElement::CleanupFunction:
136+
return nullptr;
137+
}
138+
return nullptr;
139+
}
140+
106141
unsigned getCount() const { return Count; }
107142
/// It might return null.
108143
const void *getTag() const { return SymbolTag; }
@@ -113,19 +148,20 @@ class SymbolConjured : public SymbolData {
113148

114149
void dumpToStream(raw_ostream &os) const override;
115150

116-
static void Profile(llvm::FoldingSetNodeID &profile, const Stmt *S,
151+
static void Profile(llvm::FoldingSetNodeID &profile,
152+
CFGBlock::ConstCFGElementRef ElemRef,
117153
const LocationContext *LCtx, QualType T, unsigned Count,
118154
const void *SymbolTag) {
119155
profile.AddInteger((unsigned)SymbolConjuredKind);
120-
profile.AddPointer(S);
156+
profile.Add(ElemRef);
121157
profile.AddPointer(LCtx);
122158
profile.Add(T);
123159
profile.AddInteger(Count);
124160
profile.AddPointer(SymbolTag);
125161
}
126162

127163
void Profile(llvm::FoldingSetNodeID& profile) override {
128-
Profile(profile, S, LCtx, T, Count, SymbolTag);
164+
Profile(profile, ElemRef, LCtx, T, Count, SymbolTag);
129165
}
130166

131167
// Implement isa<T> support.
@@ -533,18 +569,12 @@ class SymbolManager {
533569
template <typename SymExprT, typename... Args>
534570
const SymExprT *acquire(Args &&...args);
535571

536-
const SymbolConjured *conjureSymbol(const Stmt *E,
572+
const SymbolConjured *conjureSymbol(CFGBlock::ConstCFGElementRef ElemRef,
537573
const LocationContext *LCtx, QualType T,
538574
unsigned VisitCount,
539575
const void *SymbolTag = nullptr) {
540-
return acquire<SymbolConjured>(E, LCtx, T, VisitCount, SymbolTag);
541-
}
542576

543-
const SymbolConjured* conjureSymbol(const Expr *E,
544-
const LocationContext *LCtx,
545-
unsigned VisitCount,
546-
const void *SymbolTag = nullptr) {
547-
return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag);
577+
return acquire<SymbolConjured>(ElemRef, LCtx, T, VisitCount, SymbolTag);
548578
}
549579

550580
QualType getType(const SymExpr *SE) const {

0 commit comments

Comments
 (0)