Skip to content

Commit f01831e

Browse files
committed
[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
1 parent 3a76492 commit f01831e

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

clang/lib/StaticAnalyzer/Core/CallEvent.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,15 @@ void CXXInstanceCall::getInitialStackFrameContents(
587587
// FIXME: CallEvent maybe shouldn't be directly accessing StoreManager.
588588
bool Failed;
589589
ThisVal = StateMgr.getStoreManager().attemptDownCast(ThisVal, Ty, Failed);
590-
assert(!Failed && "Calling an incorrectly devirtualized method");
590+
if (Failed) {
591+
// We might have suffered some sort of placement new earlier, so
592+
// we're constructing in a completely unexpected storage.
593+
// Fall back to a generic pointer cast for this-value.
594+
const CXXMethodDecl *StaticMD = cast<CXXMethodDecl>(getDecl());
595+
const CXXRecordDecl *StaticClass = StaticMD->getParent();
596+
QualType StaticTy = Ctx.getPointerType(Ctx.getRecordType(StaticClass));
597+
ThisVal = SVB.evalCast(ThisVal, Ty, StaticTy);
598+
}
591599
}
592600

593601
if (!ThisVal.isUnknown())
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=core -std=c++11 -verify %s
2+
3+
// expected-no-diagnostics
4+
5+
typedef __typeof(sizeof(int)) size_t;
6+
7+
void *operator new(size_t size, void *ptr);
8+
9+
struct B {
10+
virtual void foo();
11+
};
12+
13+
struct D : public B {
14+
virtual void foo() override {}
15+
};
16+
17+
void test_ub() {
18+
// FIXME: Potentially warn because this code is pretty weird.
19+
B b;
20+
new (&b) D;
21+
b.foo(); // no-crash
22+
}
23+
24+
void test_non_ub() {
25+
char c[sizeof(D)]; // Should be enough storage.
26+
new (c) D;
27+
((B *)c)->foo(); // no-crash
28+
}

0 commit comments

Comments
 (0)