forked from OSchip/llvm-project
Fix: <rdar://problem/7275774> Static analyzer warns about NULL pointer when
adding assert This fix required a few changes: SimpleSValuator: - Eagerly replace a symbolic value with its constant value in EvalBinOpNN when it is constrained to a constant. This allows us to better constant fold values along a path. - Handle trivial case of '<', '>' comparison of pointers when the two pointers are exactly the same. RegionStoreManager: llvm-svn: 83358
This commit is contained in:
parent
c3031a9643
commit
8ec5771dcb
|
@ -548,12 +548,14 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) {
|
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
|
||||||
return SVator.EvalBinOpNN(op, L, R, T);
|
NonLoc L, NonLoc R, QualType T) {
|
||||||
|
return SVator.EvalBinOpNN(state, op, L, R, T);
|
||||||
}
|
}
|
||||||
|
|
||||||
SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) {
|
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
|
||||||
return R.isValid() ? SVator.EvalBinOpNN(op, L, cast<NonLoc>(R), T) : R;
|
NonLoc L, SVal R, QualType T) {
|
||||||
|
return R.isValid() ? SVator.EvalBinOpNN(state, op, L, cast<NonLoc>(R), T) : R;
|
||||||
}
|
}
|
||||||
|
|
||||||
SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
|
SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
|
||||||
|
|
|
@ -260,6 +260,8 @@ public:
|
||||||
|
|
||||||
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
|
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
|
||||||
|
|
||||||
|
const llvm::APSInt *getSymVal(SymbolRef sym);
|
||||||
|
|
||||||
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
|
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
|
||||||
|
|
||||||
template <typename CB> CB scanReachableSymbols(SVal val) const;
|
template <typename CB> CB scanReachableSymbols(SVal val) const;
|
||||||
|
@ -566,6 +568,10 @@ public:
|
||||||
// Out-of-line method definitions for GRState.
|
// Out-of-line method definitions for GRState.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) {
|
||||||
|
return getStateManager().getSymVal(this, sym);
|
||||||
|
}
|
||||||
|
|
||||||
inline const VarRegion* GRState::getRegion(const VarDecl *D,
|
inline const VarRegion* GRState::getRegion(const VarDecl *D,
|
||||||
const LocationContext *LC) const {
|
const LocationContext *LC) const {
|
||||||
return getStateManager().getRegionManager().getVarRegion(D, LC);
|
return getStateManager().getRegionManager().getVarRegion(D, LC);
|
||||||
|
|
|
@ -67,8 +67,8 @@ public:
|
||||||
|
|
||||||
virtual SVal EvalComplement(NonLoc val) = 0;
|
virtual SVal EvalComplement(NonLoc val) = 0;
|
||||||
|
|
||||||
virtual SVal EvalBinOpNN(BinaryOperator::Opcode Op, NonLoc lhs,
|
virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op,
|
||||||
NonLoc rhs, QualType resultTy) = 0;
|
NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
|
||||||
|
|
||||||
virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs,
|
virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs,
|
||||||
QualType resultTy) = 0;
|
QualType resultTy) = 0;
|
||||||
|
|
|
@ -2545,7 +2545,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
|
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
|
||||||
Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X,
|
Result = EvalBinOp(state, BinaryOperator::EQ, cast<NonLoc>(V), X,
|
||||||
U->getType());
|
U->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -826,7 +826,10 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
|
||||||
|
|
||||||
// Not yet handled.
|
// Not yet handled.
|
||||||
case MemRegion::VarRegionKind:
|
case MemRegion::VarRegionKind:
|
||||||
case MemRegion::StringRegionKind:
|
case MemRegion::StringRegionKind: {
|
||||||
|
|
||||||
|
}
|
||||||
|
// Fall-through.
|
||||||
case MemRegion::CompoundLiteralRegionKind:
|
case MemRegion::CompoundLiteralRegionKind:
|
||||||
case MemRegion::FieldRegionKind:
|
case MemRegion::FieldRegionKind:
|
||||||
case MemRegion::ObjCObjectRegionKind:
|
case MemRegion::ObjCObjectRegionKind:
|
||||||
|
@ -851,18 +854,28 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
|
||||||
|
|
||||||
SVal Idx = ER->getIndex();
|
SVal Idx = ER->getIndex();
|
||||||
nonloc::ConcreteInt* Base = dyn_cast<nonloc::ConcreteInt>(&Idx);
|
nonloc::ConcreteInt* Base = dyn_cast<nonloc::ConcreteInt>(&Idx);
|
||||||
nonloc::ConcreteInt* Offset = dyn_cast<nonloc::ConcreteInt>(&R);
|
|
||||||
|
|
||||||
// Only support concrete integer indexes for now.
|
// For now, only support:
|
||||||
if (Base && Offset) {
|
// (a) concrete integer indices that can easily be resolved
|
||||||
|
// (b) 0 + symbolic index
|
||||||
|
if (Base) {
|
||||||
|
if (nonloc::ConcreteInt *Offset = dyn_cast<nonloc::ConcreteInt>(&R)) {
|
||||||
// FIXME: Should use SValuator here.
|
// FIXME: Should use SValuator here.
|
||||||
SVal NewIdx = Base->evalBinOp(ValMgr, Op,
|
SVal NewIdx =
|
||||||
|
Base->evalBinOp(ValMgr, Op,
|
||||||
cast<nonloc::ConcreteInt>(ValMgr.convertToArrayIndex(*Offset)));
|
cast<nonloc::ConcreteInt>(ValMgr.convertToArrayIndex(*Offset)));
|
||||||
const MemRegion* NewER =
|
const MemRegion* NewER =
|
||||||
MRMgr.getElementRegion(ER->getElementType(), NewIdx, ER->getSuperRegion(),
|
MRMgr.getElementRegion(ER->getElementType(), NewIdx,
|
||||||
getContext());
|
ER->getSuperRegion(), getContext());
|
||||||
return ValMgr.makeLoc(NewER);
|
return ValMgr.makeLoc(NewER);
|
||||||
}
|
}
|
||||||
|
if (0 == Base->getValue()) {
|
||||||
|
const MemRegion* NewER =
|
||||||
|
MRMgr.getElementRegion(ER->getElementType(), R,
|
||||||
|
ER->getSuperRegion(), getContext());
|
||||||
|
return ValMgr.makeLoc(NewER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return UnknownVal();
|
return UnknownVal();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ SVal SValuator::EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
|
||||||
return EvalBinOpLN(ST, Op, cast<Loc>(R), cast<NonLoc>(L), T);
|
return EvalBinOpLN(ST, Op, cast<Loc>(R), cast<NonLoc>(L), T);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EvalBinOpNN(Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
|
return EvalBinOpNN(ST, Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST,
|
DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST,
|
||||||
|
|
|
@ -29,8 +29,8 @@ public:
|
||||||
|
|
||||||
virtual SVal EvalMinus(NonLoc val);
|
virtual SVal EvalMinus(NonLoc val);
|
||||||
virtual SVal EvalComplement(NonLoc val);
|
virtual SVal EvalComplement(NonLoc val);
|
||||||
virtual SVal EvalBinOpNN(BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs,
|
virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
|
||||||
QualType resultTy);
|
NonLoc lhs, NonLoc rhs, QualType resultTy);
|
||||||
virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
|
virtual SVal EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
|
||||||
QualType resultTy);
|
QualType resultTy);
|
||||||
virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
|
virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
|
||||||
|
@ -206,7 +206,8 @@ static SVal EvalEquality(ValueManager &ValMgr, Loc lhs, Loc rhs, bool isEqual,
|
||||||
return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy);
|
return ValMgr.makeTruthVal(isEqual ? lhs == rhs : lhs != rhs, resultTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
|
SVal SimpleSValuator::EvalBinOpNN(const GRState *state,
|
||||||
|
BinaryOperator::Opcode op,
|
||||||
NonLoc lhs, NonLoc rhs,
|
NonLoc lhs, NonLoc rhs,
|
||||||
QualType resultTy) {
|
QualType resultTy) {
|
||||||
// Handle trivial case where left-side and right-side are the same.
|
// Handle trivial case where left-side and right-side are the same.
|
||||||
|
@ -342,8 +343,18 @@ SVal SimpleSValuator::EvalBinOpNN(BinaryOperator::Opcode op,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case nonloc::SymbolValKind: {
|
case nonloc::SymbolValKind: {
|
||||||
|
nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
|
||||||
|
SymbolRef Sym = slhs->getSymbol();
|
||||||
|
|
||||||
|
// Does the symbol simplify to a constant?
|
||||||
|
if (Sym->getType(ValMgr.getContext())->isIntegerType())
|
||||||
|
if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
|
||||||
|
lhs = nonloc::ConcreteInt(*Constant);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (isa<nonloc::ConcreteInt>(rhs)) {
|
if (isa<nonloc::ConcreteInt>(rhs)) {
|
||||||
return ValMgr.makeNonLoc(cast<nonloc::SymbolVal>(lhs).getSymbol(), op,
|
return ValMgr.makeNonLoc(slhs->getSymbol(), op,
|
||||||
cast<nonloc::ConcreteInt>(rhs).getValue(),
|
cast<nonloc::ConcreteInt>(rhs).getValue(),
|
||||||
resultTy);
|
resultTy);
|
||||||
}
|
}
|
||||||
|
@ -362,6 +373,13 @@ SVal SimpleSValuator::EvalBinOpLL(BinaryOperator::Opcode op, Loc lhs, Loc rhs,
|
||||||
case BinaryOperator::EQ:
|
case BinaryOperator::EQ:
|
||||||
case BinaryOperator::NE:
|
case BinaryOperator::NE:
|
||||||
return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy);
|
return EvalEquality(ValMgr, lhs, rhs, op == BinaryOperator::EQ, resultTy);
|
||||||
|
case BinaryOperator::LT:
|
||||||
|
case BinaryOperator::GT:
|
||||||
|
// FIXME: Generalize. For now, just handle the trivial case where
|
||||||
|
// the two locations are identical.
|
||||||
|
if (lhs == rhs)
|
||||||
|
return ValMgr.makeTruthVal(false, resultTy);
|
||||||
|
return UnknownVal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,3 +287,19 @@ int rdar_7261075(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// <rdar://problem/7275774> false path due to limited pointer
|
||||||
|
// arithmetic constraints
|
||||||
|
void rdar_7275774(void *data, unsigned n) {
|
||||||
|
if (!(data || n == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned short *p = (unsigned short*) data;
|
||||||
|
unsigned short *q = p + (n / 2);
|
||||||
|
|
||||||
|
if (p < q) {
|
||||||
|
// If we reach here, 'p' cannot be null. If 'p' is null, then 'n' must
|
||||||
|
// be '0', meaning that this branch is not feasible.
|
||||||
|
*p = *q; // no-warning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue