[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:
parent
707c0ab755
commit
69ece336b8
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue