Enhance analyzer reasoning about sending messages to nil. A nil receiver returns 0 for scalars of size <= sizeof(void*).

llvm-svn: 68629
This commit is contained in:
Ted Kremenek 2009-04-08 18:51:08 +00:00
parent d43aaad1b1
commit 5451c60f5a
4 changed files with 51 additions and 7 deletions

View File

@ -95,6 +95,8 @@ public:
return getRawKind() > UnknownKind;
}
static SVal MakeZero(BasicValueFactory &BasicVals, QualType T);
bool isZeroConstant() const;
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
@ -211,11 +213,7 @@ class Loc : public SVal {
protected:
Loc(unsigned SubKind, const void* D)
: SVal(const_cast<void*>(D), true, SubKind) {}
// // Equality operators.
// NonLoc EQ(SymbolManager& SM, Loc R) const;
// NonLoc NE(SymbolManager& SM, Loc R) const;
public:
void print(llvm::raw_ostream& Out) const;
@ -228,6 +226,8 @@ public:
static Loc MakeVal(SymbolRef sym);
static Loc MakeNull(BasicValueFactory &BasicVals);
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind;

View File

@ -1682,7 +1682,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// "Assume" that the receiver is not NULL.
bool isFeasibleNotNull = false;
Assume(state, L, true, isFeasibleNotNull);
const GRState *StNotNull = Assume(state, L, true, isFeasibleNotNull);
// "Assume" that the receiver is NULL.
bool isFeasibleNull = false;
@ -1724,8 +1724,21 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
}
}
else {
// Handle the safe cases where the return value is 0 if the receiver
// is nil.
SVal V = SVal::MakeZero(getBasicVals(), ME->getType());
MakeNode(Dst, ME, Pred, BindExpr(StNull, ME, V));
}
}
}
// We have handled the cases where the receiver is nil. The remainder
// of this method should assume that the receiver is not nil.
if (!isFeasibleNotNull)
return;
state = StNotNull;
}
// Check if the "raise" message was sent.
@ -2445,7 +2458,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
// transfer functions as "0 == E".
if (isa<Loc>(V)) {
loc::ConcreteInt X(getBasicVals().getZeroWithPtrWidth());
Loc X = Loc::MakeNull(getBasicVals());
SVal Result = EvalBinOp(BinaryOperator::EQ, cast<Loc>(V), X,
U->getType());
state = BindExpr(state, U, Result);

View File

@ -201,6 +201,22 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
return UndefinedVal();
}
//===----------------------------------------------------------------------===//
// Utility methods for constructing SVals.
//===----------------------------------------------------------------------===//
SVal SVal::MakeZero(BasicValueFactory &BasicVals, QualType T) {
if (Loc::IsLocType(T))
return Loc::MakeNull(BasicVals);
if (T->isIntegerType())
return NonLoc::MakeVal(BasicVals, 0, T);
// FIXME: Handle floats.
// FIXME: Handle structs.
return UnknownVal();
}
//===----------------------------------------------------------------------===//
// Utility methods for constructing Non-Locs.
//===----------------------------------------------------------------------===//
@ -314,6 +330,10 @@ Loc Loc::MakeVal(AddrLabelExpr* E) { return loc::GotoLabel(E->getLabel()); }
Loc Loc::MakeVal(SymbolRef sym) { return loc::SymbolVal(sym); }
Loc Loc::MakeNull(BasicValueFactory &BasicVals) {
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
}
//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//

View File

@ -46,3 +46,14 @@ void createFoo5() {
double d = [obj doubleM]; // no-warning
}
void handleNilPruneLoop(MyClass *obj) {
if (!!obj)
return;
// Test if [obj intM] evaluates to 0, thus pruning the entire loop.
for (int i = 0; i < [obj intM]; i++) {
long long j = [obj longlongM]; // no-warning
}
long long j = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}}
}