Skip to content

Commit eeb6f61

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 b003fac commit eeb6f61

38 files changed

+563
-438
lines changed

Diff for: 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 {

Diff for: 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(const 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) {

Diff for: 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);

Diff for: 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+
const CFGBlock::ConstCFGElementRef ElemRef);
3132

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

Diff for: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
1414
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
1515

16+
#include "clang/Analysis/CFG.h"
1617
#include "clang/Basic/LLVM.h"
1718
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
1819
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
@@ -313,7 +314,8 @@ class ProgramState : public llvm::FoldingSetNode {
313314
/// be triggered by this event.
314315
///
315316
/// \param Regions the set of regions to be invalidated.
316-
/// \param E the expression that caused the invalidation.
317+
/// \param ElemRef \p CFGBlock::ConstCFGElementRef that caused the
318+
/// invalidation.
317319
/// \param BlockCount The number of times the current basic block has been
318320
/// visited.
319321
/// \param CausesPointerEscape the flag is set to true when the invalidation
@@ -325,16 +327,18 @@ class ProgramState : public llvm::FoldingSetNode {
325327
/// \param ITraits information about special handling for particular regions
326328
/// or symbols.
327329
[[nodiscard]] ProgramStateRef
328-
invalidateRegions(ArrayRef<const MemRegion *> Regions, const Stmt *S,
330+
invalidateRegions(ArrayRef<const MemRegion *> Regions,
331+
const CFGBlock::ConstCFGElementRef ElemRef,
329332
unsigned BlockCount, const LocationContext *LCtx,
330333
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
331334
const CallEvent *Call = nullptr,
332335
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
333336

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

Diff for: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h

+22-37
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 LocationContext *LCtx,
176-
QualType type,
177-
unsigned visitCount,
178-
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);
175+
const SymbolConjured *
176+
conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef,
177+
const LocationContext *LCtx, QualType type, unsigned visitCount,
178+
const void *symbolTag = nullptr) {
179+
return SymMgr.conjureSymbol(ElemRef, LCtx, type, visitCount, symbolTag);
187180
}
188181

189182
/// Construct an SVal representing '0' for the specified type.
@@ -198,32 +191,24 @@ class SValBuilder {
198191
/// The advantage of symbols derived/built from other symbols is that we
199192
/// preserve the relation between related(or even equivalent) expressions, so
200193
/// conjured symbols should be used sparingly.
201-
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
202-
const Expr *expr,
203-
const LocationContext *LCtx,
204-
unsigned count);
205-
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S,
206-
const LocationContext *LCtx,
207-
QualType type, unsigned count);
208-
DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
209-
const LocationContext *LCtx,
210-
QualType type,
211-
unsigned visitCount);
194+
DefinedOrUnknownSVal
195+
conjureSymbolVal(const void *symbolTag,
196+
const CFGBlock::ConstCFGElementRef elemRef,
197+
const LocationContext *LCtx, unsigned count);
198+
DefinedOrUnknownSVal
199+
conjureSymbolVal(const void *symbolTag,
200+
const CFGBlock::ConstCFGElementRef elemRef,
201+
const LocationContext *LCtx, QualType type, unsigned count);
202+
DefinedOrUnknownSVal
203+
conjureSymbolVal(const CFGBlock::ConstCFGElementRef elemRef,
204+
const LocationContext *LCtx, QualType type,
205+
unsigned visitCount);
212206

213207
/// 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,
225-
const LocationContext *LCtx,
226-
QualType type, unsigned Count);
208+
DefinedSVal
209+
getConjuredHeapSymbolVal(const CFGBlock::ConstCFGElementRef elemRef,
210+
const LocationContext *LCtx, QualType type,
211+
unsigned Count);
227212

228213
/// Create an SVal representing the result of an alloca()-like call, that is,
229214
/// an AllocaRegion on the stack.

Diff for: clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h

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

1616
#include "clang/AST/Type.h"
17+
#include "clang/Analysis/CFG.h"
18+
#include "clang/Basic/LLVM.h"
1719
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
1820
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
1921
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
2022
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
2123
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
2224
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
23-
#include "clang/Basic/LLVM.h"
2425
#include "llvm/ADT/ArrayRef.h"
2526
#include "llvm/ADT/DenseSet.h"
2627
#include "llvm/ADT/SmallVector.h"
@@ -223,8 +224,9 @@ class StoreManager {
223224
///
224225
/// \param[in] store The initial store.
225226
/// \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.
227+
/// \param[in] ElemRef The current \p CFGBlock::ConstCFGElementRef being
228+
/// evaluated. Used to conjure symbols to mark the values of invalidated
229+
/// regions.
228230
/// \param[in] Count The current block count. Used to conjure
229231
/// symbols to mark the values of invalidated regions.
230232
/// \param[in] Call The call expression which will be used to determine which
@@ -241,7 +243,8 @@ class StoreManager {
241243
/// even if they do not currently have bindings. Pass \c NULL if this
242244
/// information will not be used.
243245
virtual StoreRef invalidateRegions(
244-
Store store, ArrayRef<SVal> Values, const Stmt *S, unsigned Count,
246+
Store store, ArrayRef<SVal> Values,
247+
const CFGBlock::ConstCFGElementRef ElemRef, unsigned Count,
245248
const LocationContext *LCtx, const CallEvent *Call,
246249
InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits,
247250
InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0;

Diff for: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h

+56-26
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/Expr.h"
1818
#include "clang/AST/Type.h"
1919
#include "clang/Analysis/AnalysisDeclContext.h"
20+
#include "clang/Analysis/CFG.h"
2021
#include "clang/Basic/LLVM.h"
2122
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h"
2223
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -80,29 +81,63 @@ class SymbolRegionValue : public SymbolData {
8081
/// A symbol representing the result of an expression in the case when we do
8182
/// not know anything about what the expression is.
8283
class SymbolConjured : public SymbolData {
83-
const Stmt *S;
84+
const CFGBlock::ConstCFGElementRef ElemRef;
8485
QualType T;
8586
unsigned Count;
8687
const LocationContext *LCtx;
8788
const void *SymbolTag;
8889

8990
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).
91+
SymbolConjured(SymbolID sym, CFGBlock::ConstCFGElementRef elemRef,
92+
const LocationContext *lctx, QualType t, unsigned count,
93+
const void *symbolTag)
94+
: SymbolData(SymbolConjuredKind, sym), ElemRef(elemRef), T(t),
95+
Count(count), LCtx(lctx), SymbolTag(symbolTag) {
9996
assert(lctx);
10097
assert(isValidTypeForSymbol(t));
10198
}
10299

103100
public:
104-
/// It might return null.
105-
const Stmt *getStmt() const { return S; }
101+
const CFGBlock::ConstCFGElementRef getCFGElementRef() const {
102+
return ElemRef;
103+
}
104+
105+
// It might return null.
106+
const Stmt *getStmt() const {
107+
switch (ElemRef->getKind()) {
108+
case CFGElement::Initializer:
109+
return ElemRef->castAs<CFGInitializer>().getInitializer()->getInit();
110+
case CFGElement::ScopeBegin:
111+
return ElemRef->castAs<CFGScopeBegin>().getTriggerStmt();
112+
case CFGElement::ScopeEnd:
113+
return ElemRef->castAs<CFGScopeEnd>().getTriggerStmt();
114+
case CFGElement::NewAllocator:
115+
return ElemRef->castAs<CFGNewAllocator>().getAllocatorExpr();
116+
case CFGElement::LifetimeEnds:
117+
return ElemRef->castAs<CFGLifetimeEnds>().getTriggerStmt();
118+
case CFGElement::LoopExit:
119+
return ElemRef->castAs<CFGLoopExit>().getLoopStmt();
120+
case CFGElement::Statement:
121+
return ElemRef->castAs<CFGStmt>().getStmt();
122+
case CFGElement::Constructor:
123+
return ElemRef->castAs<CFGConstructor>().getStmt();
124+
case CFGElement::CXXRecordTypedCall:
125+
return ElemRef->castAs<CFGCXXRecordTypedCall>().getStmt();
126+
case CFGElement::AutomaticObjectDtor:
127+
return ElemRef->castAs<CFGAutomaticObjDtor>().getTriggerStmt();
128+
case CFGElement::DeleteDtor:
129+
return ElemRef->castAs<CFGDeleteDtor>().getDeleteExpr();
130+
case CFGElement::BaseDtor:
131+
return nullptr;
132+
case CFGElement::MemberDtor:
133+
return nullptr;
134+
case CFGElement::TemporaryDtor:
135+
return ElemRef->castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
136+
case CFGElement::CleanupFunction:
137+
return nullptr;
138+
}
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+
const 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,
537-
const LocationContext *LCtx, QualType T,
538-
unsigned VisitCount,
539-
const void *SymbolTag = nullptr) {
540-
return acquire<SymbolConjured>(E, LCtx, T, VisitCount, SymbolTag);
541-
}
572+
const SymbolConjured *
573+
conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef,
574+
const LocationContext *LCtx, QualType T, unsigned VisitCount,
575+
const void *SymbolTag = nullptr) {
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)