[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{$<UnrelatedT x>}, DerivedT}.

Differential Revision: https://reviews.llvm.org/D52189

llvm-svn: 343051
This commit is contained in:
Artem Dergachev 2018-09-26 00:17:14 +00:00
parent 707c0ab755
commit 69ece336b8
2 changed files with 41 additions and 1 deletions

View File

@ -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<SymbolicRegion>(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.

View File

@ -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<Transparent *>(ORef))->getNotInt();
}
void foo(VeryOpaqueRef ORef) {
castToDerived(reinterpret_cast<Transparent *>(ORef))->getNotInt();
}
} // namespace base_to_derived_opaque_class