[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:
Anna Zaks 2012-04-10 21:29:03 +00:00
parent c238f06a2c
commit 02ecae9282
3 changed files with 26 additions and 15 deletions

View File

@ -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()) {

View File

@ -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();

View File

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