This revision was automatically updated to reflect the committed changes.
Closed by commit rG9cbfdde2ea06: [analyzer] Fix crash with pointer to members 
values (authored by vsavchenko).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85817/new/

https://reviews.llvm.org/D85817

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/lib/StaticAnalyzer/Core/SVals.cpp
  clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
  clang/test/Analysis/PR46264.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===================================================================
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -233,39 +233,57 @@
 
 namespace testAnonymousMember {
 struct A {
+  int a;
   struct {
-    int x;
+    int b;
+    int c;
   };
   struct {
     struct {
-      int y;
+      int d;
+      int e;
     };
   };
   struct {
     union {
-      int z;
+      int f;
     };
   };
 };
 
 void test() {
-  clang_analyzer_eval(&A::x); // expected-warning{{TRUE}}
-  clang_analyzer_eval(&A::y); // expected-warning{{TRUE}}
-  clang_analyzer_eval(&A::z); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::a); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::b); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::c); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::d); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::e); // expected-warning{{TRUE}}
+  clang_analyzer_eval(&A::f); // expected-warning{{TRUE}}
+
+  int A::*ap = &A::a,
+      A::*bp = &A::b,
+      A::*cp = &A::c,
+      A::*dp = &A::d,
+      A::*ep = &A::e,
+      A::*fp = &A::f;
+
+  clang_analyzer_eval(ap); // expected-warning{{TRUE}}
+  clang_analyzer_eval(bp); // expected-warning{{TRUE}}
+  clang_analyzer_eval(cp); // expected-warning{{TRUE}}
+  clang_analyzer_eval(dp); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ep); // expected-warning{{TRUE}}
+  clang_analyzer_eval(fp); // expected-warning{{TRUE}}
 
-  // FIXME: These should be true.
-  int A::*l = &A::x, A::*m = &A::y, A::*n = &A::z;
-  clang_analyzer_eval(l); // expected-warning{{UNKNOWN}}
-  clang_analyzer_eval(m); // expected-warning{{UNKNOWN}}
-  clang_analyzer_eval(n); // expected-warning{{UNKNOWN}}
-
-  // FIXME: These should be true as well.
   A a;
-  a.x = 1;
-  clang_analyzer_eval(a.*l == 1); // expected-warning{{UNKNOWN}}
-  a.y = 2;
-  clang_analyzer_eval(a.*m == 2); // expected-warning{{UNKNOWN}}
-  a.z = 3;
-  clang_analyzer_eval(a.*n == 3); // expected-warning{{UNKNOWN}}
+  a.a = 1;
+  a.b = 2;
+  a.c = 3;
+  a.d = 4;
+  a.e = 5;
+
+  clang_analyzer_eval(a.*ap == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(a.*bp == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(a.*cp == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(a.*dp == 4); // expected-warning{{TRUE}}
+  clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
-} // end of testAnonymousMember namespace
+} // namespace testAnonymousMember
Index: clang/test/Analysis/PR46264.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/PR46264.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+// rdar://problem/64202361
+
+struct A {
+  int a;
+  struct {
+    struct {
+      int b;
+      union {
+        int c;
+      };
+    };
+  };
+};
+
+int testCrash() {
+  int *x = 0;
+  int A::*ap = &A::a;
+
+  if (ap)      // no crash
+    return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+
+  return 10;
+}
+
+int testIndirectCrash() {
+  int *x = 0;
+  int A::*cp = &A::c;
+
+  if (cp)      // no crash
+    return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+
+  return 10;
+}
Index: clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -1106,19 +1106,28 @@
 }
 
 SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
-                                  BinaryOperator::Opcode op,
-                                  Loc lhs, NonLoc rhs, QualType resultTy) {
+                                    BinaryOperator::Opcode op, Loc lhs,
+                                    NonLoc rhs, QualType resultTy) {
   if (op >= BO_PtrMemD && op <= BO_PtrMemI) {
     if (auto PTMSV = rhs.getAs<nonloc::PointerToMember>()) {
       if (PTMSV->isNullMemberPointer())
         return UndefinedVal();
-      if (const FieldDecl *FD = PTMSV->getDeclAs<FieldDecl>()) {
+
+      auto getFieldLValue = [&](const auto *FD) -> SVal {
         SVal Result = lhs;
 
         for (const auto &I : *PTMSV)
           Result = StateMgr.getStoreManager().evalDerivedToBase(
-              Result, I->getType(),I->isVirtual());
+              Result, I->getType(), I->isVirtual());
+
         return state->getLValue(FD, Result);
+      };
+
+      if (const auto *FD = PTMSV->getDeclAs<FieldDecl>()) {
+        return getFieldLValue(FD);
+      }
+      if (const auto *FD = PTMSV->getDeclAs<IndirectFieldDecl>()) {
+        return getFieldLValue(FD);
       }
     }
 
Index: clang/lib/StaticAnalyzer/Core/SVals.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -157,18 +157,18 @@
   return getPTMData().isNull();
 }
 
-const DeclaratorDecl *nonloc::PointerToMember::getDecl() const {
+const NamedDecl *nonloc::PointerToMember::getDecl() const {
   const auto PTMD = this->getPTMData();
   if (PTMD.isNull())
     return nullptr;
 
-  const DeclaratorDecl *DD = nullptr;
-  if (PTMD.is<const DeclaratorDecl *>())
-    DD = PTMD.get<const DeclaratorDecl *>();
+  const NamedDecl *ND = nullptr;
+  if (PTMD.is<const NamedDecl *>())
+    ND = PTMD.get<const NamedDecl *>();
   else
-    DD = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl();
+    ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl();
 
-  return DD;
+  return ND;
 }
 
 //===----------------------------------------------------------------------===//
@@ -185,14 +185,14 @@
 
 nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
   const PTMDataType PTMD = getPTMData();
-  if (PTMD.is<const DeclaratorDecl *>())
+  if (PTMD.is<const NamedDecl *>())
     return {};
   return PTMD.get<const PointerToMemberData *>()->begin();
 }
 
 nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
   const PTMDataType PTMD = getPTMData();
-  if (PTMD.is<const DeclaratorDecl *>())
+  if (PTMD.is<const NamedDecl *>())
     return {};
   return PTMD.get<const PointerToMemberData *>()->end();
 }
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -236,10 +236,11 @@
   return nonloc::SymbolVal(sym);
 }
 
-DefinedSVal SValBuilder::getMemberPointer(const DeclaratorDecl *DD) {
-  assert(!DD || isa<CXXMethodDecl>(DD) || isa<FieldDecl>(DD));
+DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND) {
+  assert(!ND || isa<CXXMethodDecl>(ND) || isa<FieldDecl>(ND) ||
+         isa<IndirectFieldDecl>(ND));
 
-  if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(DD)) {
+  if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(ND)) {
     // Sema treats pointers to static member functions as have function pointer
     // type, so return a function pointer for the method.
     // We don't need to play a similar trick for static member fields
@@ -249,7 +250,7 @@
       return getFunctionPointer(MD);
   }
 
-  return nonloc::PointerToMember(DD);
+  return nonloc::PointerToMember(ND);
 }
 
 DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -991,10 +991,11 @@
       if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex)) {
         const ValueDecl *VD = DRE->getDecl();
 
-        if (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD)) {
+        if (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) ||
+            isa<IndirectFieldDecl>(VD)) {
           ProgramStateRef State = (*I)->getState();
           const LocationContext *LCtx = (*I)->getLocationContext();
-          SVal SV = svalBuilder.getMemberPointer(cast<DeclaratorDecl>(VD));
+          SVal SV = svalBuilder.getMemberPointer(cast<NamedDecl>(VD));
           Bldr.generateNode(U, *I, State->BindExpr(U, LCtx, SV));
           break;
         }
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2530,16 +2530,8 @@
     return;
   }
   if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) {
-    // FIXME: Compute lvalue of field pointers-to-member.
-    // Right now we just use a non-null void pointer, so that it gives proper
-    // results in boolean contexts.
-    // FIXME: Maybe delegate this to the surrounding operator&.
-    // Note how this expression is lvalue, however pointer-to-member is NonLoc.
-    SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
-                                          currBldrCtx->blockCount());
-    state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true);
-    Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
-                      ProgramPoint::PostLValueKind);
+    // Delegate all work related to pointer to members to the surrounding
+    // operator&.
     return;
   }
   if (isa<BindingDecl>(D)) {
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -42,7 +42,7 @@
 }
 
 void PointerToMemberData::Profile(
-    llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
+    llvm::FoldingSetNodeID &ID, const NamedDecl *D,
     llvm::ImmutableList<const CXXBaseSpecifier *> L) {
   ID.AddPointer(D);
   ID.AddPointer(L.getInternalPointer());
@@ -159,17 +159,17 @@
 }
 
 const PointerToMemberData *BasicValueFactory::getPointerToMemberData(
-    const DeclaratorDecl *DD, llvm::ImmutableList<const CXXBaseSpecifier *> L) {
+    const NamedDecl *ND, llvm::ImmutableList<const CXXBaseSpecifier *> L) {
   llvm::FoldingSetNodeID ID;
-  PointerToMemberData::Profile(ID, DD, L);
+  PointerToMemberData::Profile(ID, ND, L);
   void *InsertPos;
 
   PointerToMemberData *D =
       PointerToMemberDataSet.FindNodeOrInsertPos(ID, InsertPos);
 
   if (!D) {
-    D = (PointerToMemberData*) BPAlloc.Allocate<PointerToMemberData>();
-    new (D) PointerToMemberData(DD, L);
+    D = (PointerToMemberData *)BPAlloc.Allocate<PointerToMemberData>();
+    new (D) PointerToMemberData(ND, L);
     PointerToMemberDataSet.InsertNode(D, InsertPos);
   }
 
@@ -180,25 +180,24 @@
     llvm::iterator_range<CastExpr::path_const_iterator> PathRange,
     const nonloc::PointerToMember &PTM) {
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
-  const DeclaratorDecl *DD = nullptr;
+  const NamedDecl *ND = nullptr;
   llvm::ImmutableList<const CXXBaseSpecifier *> PathList;
 
-  if (PTMDT.isNull() || PTMDT.is<const DeclaratorDecl *>()) {
-    if (PTMDT.is<const DeclaratorDecl *>())
-      DD = PTMDT.get<const DeclaratorDecl *>();
+  if (PTMDT.isNull() || PTMDT.is<const NamedDecl *>()) {
+    if (PTMDT.is<const NamedDecl *>())
+      ND = PTMDT.get<const NamedDecl *>();
 
     PathList = CXXBaseListFactory.getEmptyList();
   } else { // const PointerToMemberData *
-    const PointerToMemberData *PTMD =
-        PTMDT.get<const PointerToMemberData *>();
-    DD = PTMD->getDeclaratorDecl();
+    const PointerToMemberData *PTMD = PTMDT.get<const PointerToMemberData *>();
+    ND = PTMD->getDeclaratorDecl();
 
     PathList = PTMD->getCXXBaseList();
   }
 
   for (const auto &I : llvm::reverse(PathRange))
     PathList = prependCXXBase(I, PathList);
-  return getPointerToMemberData(DD, PathList);
+  return getPointerToMemberData(ND, PathList);
 }
 
 const llvm::APSInt*
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -520,7 +520,7 @@
 
 public:
   using PTMDataType =
-      llvm::PointerUnion<const DeclaratorDecl *, const PointerToMemberData *>;
+      llvm::PointerUnion<const NamedDecl *, const PointerToMemberData *>;
 
   const PTMDataType getPTMData() const {
     return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
@@ -528,7 +528,7 @@
 
   bool isNullMemberPointer() const;
 
-  const DeclaratorDecl *getDecl() const;
+  const NamedDecl *getDecl() const;
 
   template<typename AdjustedDecl>
   const AdjustedDecl *getDeclAs() const {
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -233,7 +233,7 @@
                                    const LocationContext *LCtx,
                                    unsigned count);
 
-  DefinedSVal getMemberPointer(const DeclaratorDecl *DD);
+  DefinedSVal getMemberPointer(const NamedDecl *ND);
 
   DefinedSVal getFunctionPointer(const FunctionDecl *func);
 
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -79,11 +79,11 @@
 };
 
 class PointerToMemberData : public llvm::FoldingSetNode {
-  const DeclaratorDecl *D;
+  const NamedDecl *D;
   llvm::ImmutableList<const CXXBaseSpecifier *> L;
 
 public:
-  PointerToMemberData(const DeclaratorDecl *D,
+  PointerToMemberData(const NamedDecl *D,
                       llvm::ImmutableList<const CXXBaseSpecifier *> L)
       : D(D), L(L) {}
 
@@ -92,11 +92,11 @@
   iterator begin() const { return L.begin(); }
   iterator end() const { return L.end(); }
 
-  static void Profile(llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
+  static void Profile(llvm::FoldingSetNodeID &ID, const NamedDecl *D,
                       llvm::ImmutableList<const CXXBaseSpecifier *> L);
 
-  void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, D, L); }
-  const DeclaratorDecl *getDeclaratorDecl() const {return D;}
+  void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, D, L); }
+  const NamedDecl *getDeclaratorDecl() const { return D; }
 
   llvm::ImmutableList<const CXXBaseSpecifier *> getCXXBaseList() const {
     return L;
@@ -236,9 +236,9 @@
   const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
                                             const TypedValueRegion *region);
 
-  const PointerToMemberData *getPointerToMemberData(
-      const DeclaratorDecl *DD,
-      llvm::ImmutableList<const CXXBaseSpecifier *> L);
+  const PointerToMemberData *
+  getPointerToMemberData(const NamedDecl *ND,
+                         llvm::ImmutableList<const CXXBaseSpecifier *> L);
 
   llvm::ImmutableList<SVal> getEmptySValList() {
     return SValListFactory.getEmptyList();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to