Skip to content

Commit 9761e66

Browse files
committed
[analyzer] Add a new SVal to support pointer-to-member operations.
Add a new type of NonLoc SVal for C++ pointer-to-member operations. This SVal supports both pointers to member functions and pointers to member data. A patch by Kirill Romanenkov! Differential Revision: https://reviews.llvm.org/D25475 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289873 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 7efb140 commit 9761e66

File tree

12 files changed

+530
-54
lines changed

12 files changed

+530
-54
lines changed

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

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,29 @@ class LazyCompoundValData : public llvm::FoldingSetNode {
5959
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
6060
};
6161

62+
class PointerToMemberData: public llvm::FoldingSetNode {
63+
const DeclaratorDecl *D;
64+
llvm::ImmutableList<const CXXBaseSpecifier *> L;
65+
66+
public:
67+
PointerToMemberData(const DeclaratorDecl *D,
68+
llvm::ImmutableList<const CXXBaseSpecifier *> L)
69+
: D(D), L(L) {}
70+
71+
typedef llvm::ImmutableList<const CXXBaseSpecifier *>::iterator iterator;
72+
iterator begin() const { return L.begin(); }
73+
iterator end() const { return L.end(); }
74+
75+
static void Profile(llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
76+
llvm::ImmutableList<const CXXBaseSpecifier *> L);
77+
78+
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, D, L); }
79+
const DeclaratorDecl *getDeclaratorDecl() const {return D;}
80+
llvm::ImmutableList<const CXXBaseSpecifier *> getCXXBaseList() const {
81+
return L;
82+
}
83+
};
84+
6285
class BasicValueFactory {
6386
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
6487
APSIntSetTy;
@@ -71,8 +94,10 @@ class BasicValueFactory {
7194
void * PersistentSValPairs;
7295

7396
llvm::ImmutableList<SVal>::Factory SValListFactory;
97+
llvm::ImmutableList<const CXXBaseSpecifier*>::Factory CXXBaseListFactory;
7498
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
7599
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
100+
llvm::FoldingSet<PointerToMemberData> PointerToMemberDataSet;
76101

77102
// This is private because external clients should use the factory
78103
// method that takes a QualType.
@@ -81,7 +106,8 @@ class BasicValueFactory {
81106
public:
82107
BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator &Alloc)
83108
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(nullptr),
84-
PersistentSValPairs(nullptr), SValListFactory(Alloc) {}
109+
PersistentSValPairs(nullptr), SValListFactory(Alloc),
110+
CXXBaseListFactory(Alloc) {}
85111

86112
~BasicValueFactory();
87113

@@ -172,14 +198,32 @@ class BasicValueFactory {
172198
const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
173199
const TypedValueRegion *region);
174200

201+
const PointerToMemberData *getPointerToMemberData(
202+
const DeclaratorDecl *DD,
203+
llvm::ImmutableList<const CXXBaseSpecifier *> L);
204+
175205
llvm::ImmutableList<SVal> getEmptySValList() {
176206
return SValListFactory.getEmptyList();
177207
}
178208

179-
llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
209+
llvm::ImmutableList<SVal> prependSVal(SVal X, llvm::ImmutableList<SVal> L) {
180210
return SValListFactory.add(X, L);
181211
}
182212

213+
llvm::ImmutableList<const CXXBaseSpecifier *> getEmptyCXXBaseList() {
214+
return CXXBaseListFactory.getEmptyList();
215+
}
216+
217+
llvm::ImmutableList<const CXXBaseSpecifier *> prependCXXBase(
218+
const CXXBaseSpecifier *CBS,
219+
llvm::ImmutableList<const CXXBaseSpecifier *> L) {
220+
return CXXBaseListFactory.add(CBS, L);
221+
}
222+
223+
const clang::ento::PointerToMemberData *accumCXXBase(
224+
llvm::iterator_range<CastExpr::path_const_iterator> PathRange,
225+
const nonloc::PointerToMember &PTM);
226+
183227
const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op,
184228
const llvm::APSInt& V1,
185229
const llvm::APSInt& V2);

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,22 @@ class ExprEngine : public SubEngine {
479479
return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X;
480480
}
481481

482+
ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
483+
const LocationContext *LCtx, QualType T,
484+
QualType ExTy, const CastExpr *CastE,
485+
StmtNodeBuilder &Bldr,
486+
ExplodedNode *Pred);
487+
488+
ProgramStateRef handleLVectorSplat(ProgramStateRef state,
489+
const LocationContext *LCtx,
490+
const CastExpr *CastE,
491+
StmtNodeBuilder &Bldr,
492+
ExplodedNode *Pred);
493+
494+
void handleUOExtension(ExplodedNodeSet::iterator I,
495+
const UnaryOperator* U,
496+
StmtNodeBuilder &Bldr);
497+
482498
public:
483499

484500
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ class SValBuilder {
204204
const LocationContext *LCtx,
205205
unsigned count);
206206

207+
DefinedSVal getMemberPointer(const DeclaratorDecl *DD);
208+
207209
DefinedSVal getFunctionPointer(const FunctionDecl *func);
208210

209211
DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
@@ -226,6 +228,14 @@ class SValBuilder {
226228
BasicVals.getLazyCompoundValData(store, region));
227229
}
228230

231+
NonLoc makePointerToMember(const DeclaratorDecl *DD) {
232+
return nonloc::PointerToMember(DD);
233+
}
234+
235+
NonLoc makePointerToMember(const PointerToMemberData *PTMD) {
236+
return nonloc::PointerToMember(PTMD);
237+
}
238+
229239
NonLoc makeZeroArrayIndex() {
230240
return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
231241
}

include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ ABSTRACT_SVAL(DefinedOrUnknownSVal, SVal)
6666
NONLOC_SVAL(LazyCompoundVal, NonLoc)
6767
NONLOC_SVAL(LocAsInteger, NonLoc)
6868
NONLOC_SVAL(SymbolVal, NonLoc)
69+
NONLOC_SVAL(PointerToMember, NonLoc)
6970

7071
#undef NONLOC_SVAL
7172
#undef LOC_SVAL

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace ento {
3232

3333
class CompoundValData;
3434
class LazyCompoundValData;
35+
class PointerToMemberData;
3536
class ProgramState;
3637
class BasicValueFactory;
3738
class MemRegion;
@@ -459,6 +460,51 @@ class LazyCompoundVal : public NonLoc {
459460
}
460461
};
461462

463+
/// \brief Value representing pointer-to-member.
464+
///
465+
/// This value is qualified as NonLoc because neither loading nor storing
466+
/// operations are aplied to it. Instead, the analyzer uses the L-value coming
467+
/// from pointer-to-member applied to an object.
468+
/// This SVal is represented by a DeclaratorDecl which can be a member function
469+
/// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
470+
/// is required to accumulate the pointer-to-member cast history to figure out
471+
/// the correct subobject field.
472+
class PointerToMember : public NonLoc {
473+
friend class ento::SValBuilder;
474+
475+
public:
476+
typedef llvm::PointerUnion<const DeclaratorDecl *,
477+
const PointerToMemberData *> PTMDataType;
478+
const PTMDataType getPTMData() const {
479+
return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
480+
}
481+
bool isNullMemberPointer() const {
482+
return getPTMData().isNull();
483+
}
484+
const DeclaratorDecl *getDecl() const;
485+
template<typename AdjustedDecl>
486+
const AdjustedDecl* getDeclAs() const {
487+
return dyn_cast_or_null<AdjustedDecl>(getDecl());
488+
}
489+
typedef llvm::ImmutableList<const CXXBaseSpecifier *>::iterator iterator;
490+
iterator begin() const;
491+
iterator end() const;
492+
493+
private:
494+
explicit PointerToMember(const PTMDataType D)
495+
: NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
496+
friend class SVal;
497+
PointerToMember() {}
498+
static bool isKind(const SVal& V) {
499+
return V.getBaseKind() == NonLocKind &&
500+
V.getSubKind() == PointerToMemberKind;
501+
}
502+
503+
static bool isKind(const NonLoc& V) {
504+
return V.getSubKind() == PointerToMemberKind;
505+
}
506+
};
507+
462508
} // end namespace ento::nonloc
463509

464510
//==------------------------------------------------------------------------==//

lib/StaticAnalyzer/Core/BasicValueFactory.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID,
3333
ID.AddPointer(region);
3434
}
3535

36+
void PointerToMemberData::Profile(
37+
llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
38+
llvm::ImmutableList<const CXXBaseSpecifier *> L) {
39+
ID.AddPointer(D);
40+
ID.AddPointer(L.getInternalPointer());
41+
}
42+
3643
typedef std::pair<SVal, uintptr_t> SValData;
3744
typedef std::pair<SVal, SVal> SValPair;
3845

@@ -142,6 +149,49 @@ BasicValueFactory::getLazyCompoundValData(const StoreRef &store,
142149
return D;
143150
}
144151

152+
const PointerToMemberData *BasicValueFactory::getPointerToMemberData(
153+
const DeclaratorDecl *DD, llvm::ImmutableList<const CXXBaseSpecifier*> L) {
154+
llvm::FoldingSetNodeID ID;
155+
PointerToMemberData::Profile(ID, DD, L);
156+
void *InsertPos;
157+
158+
PointerToMemberData *D =
159+
PointerToMemberDataSet.FindNodeOrInsertPos(ID, InsertPos);
160+
161+
if (!D) {
162+
D = (PointerToMemberData*) BPAlloc.Allocate<PointerToMemberData>();
163+
new (D) PointerToMemberData(DD, L);
164+
PointerToMemberDataSet.InsertNode(D, InsertPos);
165+
}
166+
167+
return D;
168+
}
169+
170+
const clang::ento::PointerToMemberData *BasicValueFactory::accumCXXBase(
171+
llvm::iterator_range<CastExpr::path_const_iterator> PathRange,
172+
const nonloc::PointerToMember &PTM) {
173+
nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
174+
const DeclaratorDecl *DD = nullptr;
175+
llvm::ImmutableList<const CXXBaseSpecifier *> PathList;
176+
177+
if (PTMDT.isNull() || PTMDT.is<const DeclaratorDecl *>()) {
178+
if (PTMDT.is<const DeclaratorDecl *>())
179+
DD = PTMDT.get<const DeclaratorDecl *>();
180+
181+
PathList = CXXBaseListFactory.getEmptyList();
182+
} else { // const PointerToMemberData *
183+
const PointerToMemberData *PTMD =
184+
PTMDT.get<const PointerToMemberData *>();
185+
DD = PTMD->getDeclaratorDecl();
186+
187+
PathList = PTMD->getCXXBaseList();
188+
}
189+
190+
for (const auto &I : llvm::reverse(PathRange))
191+
PathList = prependCXXBase(I, PathList);
192+
return getPointerToMemberData(DD, PathList);
193+
}
194+
145195
const llvm::APSInt*
146196
BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
147197
const llvm::APSInt& V1, const llvm::APSInt& V2) {

0 commit comments

Comments
 (0)