diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/MemRegion.cpp | 32 | ||||
-rw-r--r-- | test/Analysis/reinterpret-cast.cpp | 22 |
2 files changed, 54 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index e1b8b186c7..12e43537aa 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -1092,6 +1092,23 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const { return RegionRawOffset(superR, offset); } + +/// Returns true if \p Base is an immediate base class of \p Child +static bool isImmediateBase(const CXXRecordDecl *Child, + const CXXRecordDecl *Base) { + // Note that we do NOT canonicalize the base class here, because + // ASTRecordLayout doesn't either. If that leads us down the wrong path, + // so be it; at least we won't crash. + for (CXXRecordDecl::base_class_const_iterator I = Child->bases_begin(), + E = Child->bases_end(); + I != E; ++I) { + if (I->getType()->getAsCXXRecordDecl() == Base) + return true; + } + + return false; +} + RegionOffset MemRegion::getAsOffset() const { const MemRegion *R = this; const MemRegion *SymbolicOffsetBase = 0; @@ -1145,6 +1162,7 @@ RegionOffset MemRegion::getAsOffset() const { R = BOR->getSuperRegion(); QualType Ty; + bool RootIsSymbolic = false; if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) { Ty = TVR->getDesugaredValueType(getContext()); } else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) { @@ -1152,6 +1170,7 @@ RegionOffset MemRegion::getAsOffset() const { // Pretend the type of the symbol is the true dynamic type. // (This will at least be self-consistent for the life of the symbol.) Ty = SR->getSymbol()->getType()->getPointeeType(); + RootIsSymbolic = true; } const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl(); @@ -1160,6 +1179,19 @@ RegionOffset MemRegion::getAsOffset() const { SymbolicOffsetBase = R; } + if (RootIsSymbolic) { + // Base layers on symbolic regions may not be type-correct. + // Double-check the inheritance here, and revert to a symbolic offset + // if it's invalid (e.g. due to a reinterpret_cast). + if (BOR->isVirtual()) { + if (!Child->isVirtuallyDerivedFrom(BOR->getDecl())) + SymbolicOffsetBase = R; + } else { + if (!isImmediateBase(Child, BOR->getDecl())) + SymbolicOffsetBase = R; + } + } + // Don't bother calculating precise offsets if we already have a // symbolic offset somewhere in the chain. if (SymbolicOffsetBase) diff --git a/test/Analysis/reinterpret-cast.cpp b/test/Analysis/reinterpret-cast.cpp index d1aed80a0c..59e6a539a1 100644 --- a/test/Analysis/reinterpret-cast.cpp +++ b/test/Analysis/reinterpret-cast.cpp @@ -64,3 +64,25 @@ namespace rdar13249297 { clang_analyzer_eval(reinterpret_cast<IntWrapperSubclass *>(ww)->x == 42); // expected-warning{{FALSE}} } } + +namespace PR15345 { + class C {}; + + class Base { + public: + void (*f)(); + int x; + }; + + class Derived : public Base {}; + + void test() { + Derived* p; + *(reinterpret_cast<void**>(&p)) = new C; + p->f(); + + // We should still be able to do some reasoning about bindings. + p->x = 42; + clang_analyzer_eval(p->x == 42); // expected-warning{{TRUE}} + }; +} |