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);
|
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()) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue