forked from OSchip/llvm-project
[analyzer] dynamic_cast: Better model cast from a reference.
Generate a sink when the dynamic_cast from a reference fails to represent a thrown exception. llvm-svn: 154438
This commit is contained in:
parent
c238f06a2c
commit
02ecae9282
|
@ -304,14 +304,21 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
val = getStoreManager().evalDynamicCast(val, T, Failed);
|
||||
|
||||
if (Failed) {
|
||||
// If the cast fails, conjure symbol constrained to 0.
|
||||
DefinedOrUnknownSVal NewSym = svalBuilder.getConjuredSymbolVal(NULL,
|
||||
CastE, LCtx, resultType,
|
||||
currentBuilderContext->getCurrentBlockCount());
|
||||
DefinedOrUnknownSVal Constraint = svalBuilder.evalEQ(state,
|
||||
NewSym, svalBuilder.makeZeroVal(resultType));
|
||||
state = state->assume(Constraint, true);
|
||||
state = state->BindExpr(CastE, LCtx, NewSym);
|
||||
if (T->isReferenceType()) {
|
||||
// A bad_cast exception is thrown if input value is a reference.
|
||||
// Currently, we model this, by generating a sink.
|
||||
Bldr.generateNode(CastE, Pred, state, true);
|
||||
continue;
|
||||
} else {
|
||||
// If the cast fails on a pointer, conjure symbol constrained to 0.
|
||||
DefinedOrUnknownSVal NewSym = svalBuilder.getConjuredSymbolVal(NULL,
|
||||
CastE, LCtx, resultType,
|
||||
currentBuilderContext->getCurrentBlockCount());
|
||||
DefinedOrUnknownSVal Constraint = svalBuilder.evalEQ(state,
|
||||
NewSym, svalBuilder.makeZeroVal(resultType));
|
||||
state = state->assume(Constraint, true);
|
||||
state = state->BindExpr(CastE, LCtx, NewSym);
|
||||
}
|
||||
} else {
|
||||
// If we don't know if the cast succeeded, conjure a new symbol.
|
||||
if (val.isUnknown()) {
|
||||
|
|
|
@ -896,11 +896,7 @@ SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType,
|
|||
return UnknownVal();
|
||||
const MemRegion *BaseRegion = baseRegVal->stripCasts();
|
||||
|
||||
// Assume the derived class is a pointer to a CXX record.
|
||||
// TODO: Note, we do not model reference types: a bad_cast exception is thrown
|
||||
// when a cast of reference fails, but we just return an UnknownVal.
|
||||
if (!derivedType->isPointerType())
|
||||
return UnknownVal();
|
||||
// Assume the derived class is a pointer or a reference to a CXX record.
|
||||
derivedType = derivedType->getPointeeType();
|
||||
assert(!derivedType.isNull());
|
||||
const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl();
|
||||
|
|
|
@ -167,10 +167,18 @@ int testCastToVoidStar() {
|
|||
return *res; // no warning
|
||||
}
|
||||
|
||||
int testReference() {
|
||||
int testReferenceSuccesfulCast() {
|
||||
B rb;
|
||||
B &b = dynamic_cast<B&>(rb);
|
||||
int *x = 0;
|
||||
return *x; // expected-warning {{Dereference of null pointer}}
|
||||
}
|
||||
|
||||
int testReferenceFailedCast() {
|
||||
A a;
|
||||
B &b = dynamic_cast<B&>(a);
|
||||
return b.m; // no warning
|
||||
int *x = 0;
|
||||
return *x; // no warning (An exception is thrown by the cast.)
|
||||
}
|
||||
|
||||
// False negatives.
|
||||
|
|
Loading…
Reference in New Issue