summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 20:54:40 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 20:54:40 +0000
commitf01831ebe9fb1a9395318d4f5f854ee9d862a359 (patch)
tree211493f141a68b91d15582849604c2f77a07496a
parent3a76492108d82aad3e497984f59b3822cc8490d2 (diff)
downloadbcm5719-llvm-f01831ebe9fb1a9395318d4f5f854ee9d862a359.tar.gz
bcm5719-llvm-f01831ebe9fb1a9395318d4f5f854ee9d862a359.zip
[analyzer] Don't crash when dynamic type of a variable is set via placement new.
If a variable or an otherwise a concrete typed-value region is being placement-new'ed into, its dynamic type may change in arbitrary manners. And when the region is used, there may be a third type that's different from both the static and the dynamic type. It cannot be *completely* different from the dynamic type, but it may be a base class of the dynamic type - and in this case there isn't (and shouldn't be) any indication anywhere in the AST that there is a derived-to-base cast from the dynamic type to the third type. Perform a generic cast (evalCast()) from the third type to the dynamic type in this case. From the point of view of the SVal hierarchy, this would have produced non-canonical SVals if we used such generic cast in the normal case, but in this case there doesn't seem to be a better option. Differential Revision: https://reviews.llvm.org/D43659 llvm-svn: 326245
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp10
-rw-r--r--clang/test/Analysis/new-dynamic-types.cpp28
2 files changed, 37 insertions, 1 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index cb41f65e988..47a10bf23c4 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -587,7 +587,15 @@ void CXXInstanceCall::getInitialStackFrameContents(
// FIXME: CallEvent maybe shouldn't be directly accessing StoreManager.
bool Failed;
ThisVal = StateMgr.getStoreManager().attemptDownCast(ThisVal, Ty, Failed);
- assert(!Failed && "Calling an incorrectly devirtualized method");
+ if (Failed) {
+ // We might have suffered some sort of placement new earlier, so
+ // we're constructing in a completely unexpected storage.
+ // Fall back to a generic pointer cast for this-value.
+ const CXXMethodDecl *StaticMD = cast<CXXMethodDecl>(getDecl());
+ const CXXRecordDecl *StaticClass = StaticMD->getParent();
+ QualType StaticTy = Ctx.getPointerType(Ctx.getRecordType(StaticClass));
+ ThisVal = SVB.evalCast(ThisVal, Ty, StaticTy);
+ }
}
if (!ThisVal.isUnknown())
diff --git a/clang/test/Analysis/new-dynamic-types.cpp b/clang/test/Analysis/new-dynamic-types.cpp
new file mode 100644
index 00000000000..e0a460e3928
--- /dev/null
+++ b/clang/test/Analysis/new-dynamic-types.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -std=c++11 -verify %s
+
+// expected-no-diagnostics
+
+typedef __typeof(sizeof(int)) size_t;
+
+void *operator new(size_t size, void *ptr);
+
+struct B {
+ virtual void foo();
+};
+
+struct D : public B {
+ virtual void foo() override {}
+};
+
+void test_ub() {
+ // FIXME: Potentially warn because this code is pretty weird.
+ B b;
+ new (&b) D;
+ b.foo(); // no-crash
+}
+
+void test_non_ub() {
+ char c[sizeof(D)]; // Should be enough storage.
+ new (c) D;
+ ((B *)c)->foo(); // no-crash
+}
OpenPOWER on IntegriCloud