]> granicus.if.org Git - clang/commitdiff
[analyzer] Treat pointers to static member functions as function pointers
authorDevin Coughlin <dcoughlin@apple.com>
Tue, 10 Jan 2017 18:49:27 +0000 (18:49 +0000)
committerDevin Coughlin <dcoughlin@apple.com>
Tue, 10 Jan 2017 18:49:27 +0000 (18:49 +0000)
Sema treats pointers to static member functions as having function pointer
type, so treat treat them as function pointer values in the analyzer as well.
This prevents an assertion failure in SValBuilder::evalBinOp caused by code
that expects function pointers to be Locs (in contrast, PointerToMember values
are nonlocs).

Differential Revision: https://reviews.llvm.org/D28033

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291581 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/SValBuilder.cpp
test/Analysis/pointer-to-member.cpp

index 10b0858b848874f5ff73162fc8e105e0de54a32a..ffaa0eda918aa9e4ecadd830b1dcd217ea9a1fa6 100644 (file)
@@ -218,6 +218,18 @@ SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
 }
 
 DefinedSVal SValBuilder::getMemberPointer(const DeclaratorDecl* DD) {
+  assert(!DD || isa<CXXMethodDecl>(DD) || isa<FieldDecl>(DD));
+
+  if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(DD)) {
+    // 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
+    // because these are represented as plain VarDecls and not FieldDecls
+    // in the AST.
+    if (MD->isStatic())
+      return getFunctionPointer(MD);
+  }
+
   return nonloc::PointerToMember(DD);
 }
 
index eef20627a13290ea041d3df9667f4c951c3d5991..039782b44b747e5faf746b634641ef22b3b081b3 100644 (file)
@@ -77,7 +77,8 @@ bool testDereferencing() {
 namespace testPointerToMemberFunction {
   struct A {
     virtual int foo() { return 1; }
-    int bar() { return 2;  }
+    int bar() { return 2; }
+    int static staticMemberFunction(int p) { return p + 1; };
   };
 
   struct B : public A {
@@ -111,11 +112,19 @@ namespace testPointerToMemberFunction {
 
     clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}}
   }
+
+  void testPointerToStaticMemberCall() {
+    int (*fPtr)(int) = &A::staticMemberFunction;
+    if (fPtr != 0) { // no-crash
+      clang_analyzer_eval(fPtr(2) == 3); // expected-warning{{TRUE}}
+    }
+  }
 } // end of testPointerToMemberFunction namespace
 
 namespace testPointerToMemberData {
   struct A {
     int i;
+    static int j;
   };
 
   void testPointerToMemberData() {
@@ -126,6 +135,13 @@ namespace testPointerToMemberData {
     a.*AMdPointer += 1;
 
     clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}}
+
+    int *ptrToStaticField = &A::j;
+    if (ptrToStaticField != 0) {
+      *ptrToStaticField = 7;
+      clang_analyzer_eval(*ptrToStaticField == 7); // expected-warning{{TRUE}}
+      clang_analyzer_eval(A::j == 7); // expected-warning{{TRUE}}
+    }
   }
 } // end of testPointerToMemberData namespace