diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -82,12 +82,13 @@ class PointerToMemberData : public llvm::FoldingSetNode { const NamedDecl *D; + QualType T; llvm::ImmutableList L; public: - PointerToMemberData(const NamedDecl *D, + PointerToMemberData(const NamedDecl *D, QualType T, llvm::ImmutableList L) - : D(D), L(L) {} + : D(D), T(T), L(L) {} using iterator = llvm::ImmutableList::iterator; @@ -95,11 +96,14 @@ iterator end() const { return L.end(); } static void Profile(llvm::FoldingSetNodeID &ID, const NamedDecl *D, + QualType T, llvm::ImmutableList L); - void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, D, L); } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, D, T, L); } const NamedDecl *getDeclaratorDecl() const { return D; } + QualType getType() const { return T; } + llvm::ImmutableList getCXXBaseList() const { return L; } @@ -241,11 +245,16 @@ const CompoundValData *getCompoundValData(QualType T, llvm::ImmutableList Vals); - const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store, - const TypedValueRegion *region); + const LazyCompoundValData * + getLazyCompoundValData(const StoreRef &store, const TypedValueRegion *region); + + const PointerToMemberData *getPointerToMemberData(const NamedDecl *ND, + QualType T) { + return getPointerToMemberData(ND, T, CXXBaseListFactory.getEmptyList()); + } const PointerToMemberData * - getPointerToMemberData(const NamedDecl *ND, + getPointerToMemberData(const NamedDecl *ND, QualType T, llvm::ImmutableList L); llvm::ImmutableList getEmptySValList() { diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -247,7 +247,7 @@ const LocationContext *LCtx, unsigned count); - DefinedSVal getMemberPointer(const NamedDecl *ND); + DefinedSVal getMemberPointer(const NamedDecl *ND, QualType T); DefinedSVal getFunctionPointer(const FunctionDecl *func); @@ -271,10 +271,6 @@ BasicVals.getLazyCompoundValData(store, region)); } - NonLoc makePointerToMember(const DeclaratorDecl *DD) { - return nonloc::PointerToMember(DD); - } - NonLoc makePointerToMember(const PointerToMemberData *PTMD) { return nonloc::PointerToMember(PTMD); } diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -523,17 +523,16 @@ friend class ento::SValBuilder; public: - using PTMDataType = - llvm::PointerUnion; - - const PTMDataType getPTMData() const { - return PTMDataType::getFromOpaqueValue(const_cast(Data)); + const PointerToMemberData *getPTMData() const { + return static_cast(Data); } bool isNullMemberPointer() const; const NamedDecl *getDecl() const; + QualType getType() const; + template const AdjustedDecl *getDeclAs() const { return dyn_cast_or_null(getDecl()); @@ -548,8 +547,8 @@ friend class SVal; PointerToMember() = default; - explicit PointerToMember(const PTMDataType D) - : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {} + explicit PointerToMember(const PointerToMemberData *D) + : NonLoc(PointerToMemberKind, D) {} static bool isKind(const SVal& V) { return V.getBaseKind() == NonLocKind && diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp --- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -43,9 +43,10 @@ } void PointerToMemberData::Profile( - llvm::FoldingSetNodeID &ID, const NamedDecl *D, + llvm::FoldingSetNodeID &ID, const NamedDecl *D, QualType T, llvm::ImmutableList L) { ID.AddPointer(D); + ID.AddPointer(T.getAsOpaquePtr()); ID.AddPointer(L.getInternalPointer()); } @@ -160,9 +161,10 @@ } const PointerToMemberData *BasicValueFactory::getPointerToMemberData( - const NamedDecl *ND, llvm::ImmutableList L) { + const NamedDecl *ND, QualType T, + llvm::ImmutableList L) { llvm::FoldingSetNodeID ID; - PointerToMemberData::Profile(ID, ND, L); + PointerToMemberData::Profile(ID, ND, T, L); void *InsertPos; PointerToMemberData *D = @@ -170,7 +172,7 @@ if (!D) { D = (PointerToMemberData *)BPAlloc.Allocate(); - new (D) PointerToMemberData(ND, L); + new (D) PointerToMemberData(ND, T, L); PointerToMemberDataSet.InsertNode(D, InsertPos); } @@ -196,21 +198,9 @@ kind == CK_BaseToDerivedMemberPointer || kind == CK_ReinterpretMemberPointer) && "accumCXXBase called with wrong CastKind"); - nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData(); - const NamedDecl *ND = nullptr; - llvm::ImmutableList BaseSpecList; - - if (PTMDT.isNull() || PTMDT.is()) { - if (PTMDT.is()) - ND = PTMDT.get(); - - BaseSpecList = CXXBaseListFactory.getEmptyList(); - } else { - const PointerToMemberData *PTMD = PTMDT.get(); - ND = PTMD->getDeclaratorDecl(); - - BaseSpecList = PTMD->getCXXBaseList(); - } + const PointerToMemberData *PTMD = PTM.getPTMData(); + llvm::ImmutableList BaseSpecList = + PTMD->getCXXBaseList(); assert(hasNoRepeatedElements(BaseSpecList) && "CXXBaseSpecifier list of PointerToMemberData must not have repeated " @@ -237,13 +227,15 @@ CXXBaseListFactory.add(BaseSpec, ReducedBaseSpecList); } - return getPointerToMemberData(ND, ReducedBaseSpecList); + return getPointerToMemberData(PTMD->getDeclaratorDecl(), PTMD->getType(), + ReducedBaseSpecList); } // FIXME: Reinterpret casts on member-pointers are not handled properly by // this code for (const CXXBaseSpecifier *I : llvm::reverse(PathRange)) BaseSpecList = prependCXXBase(I, BaseSpecList); - return getPointerToMemberData(ND, BaseSpecList); + return getPointerToMemberData(PTMD->getDeclaratorDecl(), PTMD->getType(), + BaseSpecList); } const llvm::APSInt* diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -516,7 +516,7 @@ continue; } case CK_NullToMemberPointer: { - SVal V = svalBuilder.getMemberPointer(nullptr); + SVal V = svalBuilder.getMemberPointer(nullptr, CastE->getType()); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; @@ -1000,7 +1000,8 @@ isa(VD)) { ProgramStateRef State = (*I)->getState(); const LocationContext *LCtx = (*I)->getLocationContext(); - SVal SV = svalBuilder.getMemberPointer(cast(VD)); + SVal SV = + svalBuilder.getMemberPointer(cast(VD), U->getType()); Bldr.generateNode(U, *I, State->BindExpr(U, LCtx, SV)); break; } diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -236,7 +236,7 @@ return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND) { +DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND, QualType T) { assert(!ND || isa(ND) || isa(ND) || isa(ND)); @@ -250,7 +250,8 @@ return getFunctionPointer(MD); } - return nonloc::PointerToMember(ND); + return nonloc::PointerToMember( + ND ? getBasicValueFactory().getPointerToMemberData(ND, T) : nullptr); } DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) { diff --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp --- a/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -180,6 +180,14 @@ Optional VisitNonLocSymbolVal(nonloc::SymbolVal SV) { return Visit(SV.getSymbol()); } + Optional VisitNonLocPointerToMember(nonloc::PointerToMember PTM) { + QualType T = PTM.getType(); + + if (T.isNull()) + return None; + + return T; + } Optional VisitSymbolicRegion(const SymbolicRegion *SR) { return Visit(SR->getSymbol()); } @@ -209,21 +217,21 @@ } bool nonloc::PointerToMember::isNullMemberPointer() const { - return getPTMData().isNull(); + return getPTMData() == nullptr; } const NamedDecl *nonloc::PointerToMember::getDecl() const { - const auto PTMD = this->getPTMData(); - if (PTMD.isNull()) + if (!getPTMData()) return nullptr; - const NamedDecl *ND = nullptr; - if (PTMD.is()) - ND = PTMD.get(); - else - ND = PTMD.get()->getDeclaratorDecl(); + return getPTMData()->getDeclaratorDecl(); +} + +QualType nonloc::PointerToMember::getType() const { + if (!getPTMData()) + return {}; - return ND; + return getPTMData()->getType(); } //===----------------------------------------------------------------------===// @@ -239,17 +247,11 @@ } nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const { - const PTMDataType PTMD = getPTMData(); - if (PTMD.is()) - return {}; - return PTMD.get()->begin(); + return getPTMData()->begin(); } nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const { - const PTMDataType PTMD = getPTMData(); - if (PTMD.is()) - return {}; - return PTMD.get()->end(); + return getPTMData()->end(); } //===----------------------------------------------------------------------===// diff --git a/clang/unittests/StaticAnalyzer/SValTest.cpp b/clang/unittests/StaticAnalyzer/SValTest.cpp --- a/clang/unittests/StaticAnalyzer/SValTest.cpp +++ b/clang/unittests/StaticAnalyzer/SValTest.cpp @@ -346,6 +346,41 @@ EXPECT_EQ(Context.VoidPtrTy, *B.getType(Context)); } +SVAL_TEST(GetMemberPtrType, R"( +struct A { + int a; + struct { + int b; + }; +}; +void foo(int A::*x) { + int A::*a = &A::a; + int A::*b = &A::b; + int A::*c = x; +} +)") { + SVal A = getByName("a"); + ASSERT_TRUE(A.getType(Context).hasValue()); + const auto *AMemberPtrTy = dyn_cast(*A.getType(Context)); + ASSERT_NE(AMemberPtrTy, nullptr); + EXPECT_EQ(Context.IntTy, AMemberPtrTy->getPointeeType()); + const auto *ARecordType = dyn_cast(AMemberPtrTy->getClass()); + ASSERT_NE(ARecordType, nullptr); + EXPECT_EQ("A", ARecordType->getDecl()->getName()); + + SVal B = getByName("b"); + ASSERT_TRUE(B.getType(Context).hasValue()); + const auto *BMemberPtrTy = dyn_cast(*B.getType(Context)); + ASSERT_NE(BMemberPtrTy, nullptr); + EXPECT_EQ(Context.IntTy, BMemberPtrTy->getPointeeType()); + const auto *BRecordType = dyn_cast(BMemberPtrTy->getClass()); + ASSERT_NE(BRecordType, nullptr); + EXPECT_EQ("A", BRecordType->getDecl()->getName()); + + SVal C = getByName("c"); + EXPECT_TRUE(C.isUnknown()); +} + } // namespace } // namespace ento } // namespace clang