From: Artem Dergachev Date: Wed, 26 Sep 2018 00:17:14 +0000 (+0000) Subject: [analyzer] Fix a crash on casting symbolic pointers to derived classes. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8e0f894a0e674223969246d91e61416de9bfb133;p=clang [analyzer] Fix a crash on casting symbolic pointers to derived classes. Commit r340984 causes a crash when a pointer to a completely unrelated type UnrelatedT (eg., opaque struct pattern) is being casted from base class BaseT to derived class DerivedT, which results in an ill-formed region Derived{SymRegion{$}, DerivedT}. Differential Revision: https://reviews.llvm.org/D52189 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@343051 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index c3b706d90f..cc9939a68d 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -375,8 +375,18 @@ SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType, MR = Uncasted; } + // If we're casting a symbolic base pointer to a derived class, use + // CXXDerivedObjectRegion to represent the cast. If it's a pointer to an + // unrelated type, it must be a weird reinterpret_cast and we have to + // be fine with ElementRegion. TODO: Should we instead make + // Derived{TargetClass, Element{SourceClass, SR}}? if (const auto *SR = dyn_cast(MR)) { - return loc::MemRegionVal(MRMgr.getCXXDerivedObjectRegion(TargetClass, SR)); + QualType T = SR->getSymbol()->getType(); + const CXXRecordDecl *SourceClass = T->getPointeeCXXRecordDecl(); + if (TargetClass && SourceClass && TargetClass->isDerivedFrom(SourceClass)) + return loc::MemRegionVal( + MRMgr.getCXXDerivedObjectRegion(TargetClass, SR)); + return loc::MemRegionVal(GetElementZeroRegion(SR, TargetType)); } // We failed if the region we ended up with has perfect type info. diff --git a/test/Analysis/casts.cpp b/test/Analysis/casts.cpp index 9b3e294c77..2c29105279 100644 --- a/test/Analysis/casts.cpp +++ b/test/Analysis/casts.cpp @@ -70,5 +70,35 @@ void foo(B *b) { clang_analyzer_eval(c->x); // expected-warning{{UNKNOWN}} clang_analyzer_eval(c->y); // expected-warning{{TRUE}} } +} // namespace base_to_derived_double_inheritance + +namespace base_to_derived_opaque_class { +class NotInt { +public: + operator int() { return !x; } // no-crash + int x; +}; + +typedef struct Opaque *OpaqueRef; +typedef void *VeryOpaqueRef; + +class Transparent { +public: + int getNotInt() { return NI; } + NotInt NI; +}; + +class SubTransparent : public Transparent {}; + +SubTransparent *castToDerived(Transparent *TRef) { + return (SubTransparent *)TRef; } +void foo(OpaqueRef ORef) { + castToDerived(reinterpret_cast(ORef))->getNotInt(); +} + +void foo(VeryOpaqueRef ORef) { + castToDerived(reinterpret_cast(ORef))->getNotInt(); +} +} // namespace base_to_derived_opaque_class