[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); val = getStoreManager().evalDynamicCast(val, T, Failed);
if (Failed) { if (Failed) {
// If the cast fails, conjure symbol constrained to 0. if (T->isReferenceType()) {
DefinedOrUnknownSVal NewSym = svalBuilder.getConjuredSymbolVal(NULL, // A bad_cast exception is thrown if input value is a reference.
CastE, LCtx, resultType, // Currently, we model this, by generating a sink.
currentBuilderContext->getCurrentBlockCount()); Bldr.generateNode(CastE, Pred, state, true);
DefinedOrUnknownSVal Constraint = svalBuilder.evalEQ(state, continue;
NewSym, svalBuilder.makeZeroVal(resultType)); } else {
state = state->assume(Constraint, true); // If the cast fails on a pointer, conjure symbol constrained to 0.
state = state->BindExpr(CastE, LCtx, NewSym); 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 { } else {
// If we don't know if the cast succeeded, conjure a new symbol. // If we don't know if the cast succeeded, conjure a new symbol.
if (val.isUnknown()) { if (val.isUnknown()) {

View File

@ -896,11 +896,7 @@ SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType,
return UnknownVal(); return UnknownVal();
const MemRegion *BaseRegion = baseRegVal->stripCasts(); const MemRegion *BaseRegion = baseRegVal->stripCasts();
// Assume the derived class is a pointer to a CXX record. // Assume the derived class is a pointer or a reference 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();
derivedType = derivedType->getPointeeType(); derivedType = derivedType->getPointeeType();
assert(!derivedType.isNull()); assert(!derivedType.isNull());
const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl(); const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl();

View File

@ -167,10 +167,18 @@ int testCastToVoidStar() {
return *res; // no warning 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; A a;
B &b = dynamic_cast<B&>(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. // False negatives.