summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDevin Coughlin <dcoughlin@apple.com>2017-01-10 18:49:27 +0000
committerDevin Coughlin <dcoughlin@apple.com>2017-01-10 18:49:27 +0000
commite18cc41c810ed8ecb807d63c27773fb3f08aeb00 (patch)
tree217ce639d231ac5e4b43a3105a1f22fd2b1f6a46
parent69518aa6dac03bc7c3779a42caa861e4b971c316 (diff)
[analyzer] Treat pointers to static member functions as function pointers
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
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp12
-rw-r--r--test/Analysis/pointer-to-member.cpp18
2 files changed, 29 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 10b0858b84..ffaa0eda91 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -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);
}
diff --git a/test/Analysis/pointer-to-member.cpp b/test/Analysis/pointer-to-member.cpp
index eef20627a1..039782b44b 100644
--- a/test/Analysis/pointer-to-member.cpp
+++ b/test/Analysis/pointer-to-member.cpp
@@ -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