Also adds a getKnownValue() method to SValuator, which gets the integer value of an SVal if it is known to only have one possible value. There are more places in the code that could be using this, but in general we want to be dealing entirely in SVals, so its usefulness is limited. The only visible functionality change is that extents are now honored for any DeclRegion, such as fields and Objective-C ivars, rather than just variables. This shows up in bounds-checking and cast-size-checking. llvm-svn: 107577
844 lines
31 KiB
C++
844 lines
31 KiB
C++
// SimpleSValuator.cpp - A basic SValuator ------------------------*- C++ -*--//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines SimpleSValuator, a basic implementation of SValuator.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Checker/PathSensitive/SValuator.h"
|
|
#include "clang/Checker/PathSensitive/GRState.h"
|
|
|
|
using namespace clang;
|
|
|
|
namespace {
|
|
class SimpleSValuator : public SValuator {
|
|
protected:
|
|
virtual SVal EvalCastNL(NonLoc val, QualType castTy);
|
|
virtual SVal EvalCastL(Loc val, QualType castTy);
|
|
|
|
public:
|
|
SimpleSValuator(ValueManager &valMgr) : SValuator(valMgr) {}
|
|
virtual ~SimpleSValuator() {}
|
|
|
|
virtual SVal EvalMinus(NonLoc val);
|
|
virtual SVal EvalComplement(NonLoc val);
|
|
virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
|
|
NonLoc lhs, NonLoc rhs, QualType resultTy);
|
|
virtual SVal EvalBinOpLL(const GRState *state, BinaryOperator::Opcode op,
|
|
Loc lhs, Loc rhs, QualType resultTy);
|
|
virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
|
|
Loc lhs, NonLoc rhs, QualType resultTy);
|
|
|
|
/// getKnownValue - Evaluates a given SVal. If the SVal has only one possible
|
|
/// (integer) value, that value is returned. Otherwise, returns NULL.
|
|
virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V);
|
|
|
|
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
|
|
const llvm::APSInt &RHS, QualType resultTy);
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
SValuator *clang::CreateSimpleSValuator(ValueManager &valMgr) {
|
|
return new SimpleSValuator(valMgr);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Transfer function for Casts.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) {
|
|
|
|
bool isLocType = Loc::IsLocType(castTy);
|
|
|
|
if (nonloc::LocAsInteger *LI = dyn_cast<nonloc::LocAsInteger>(&val)) {
|
|
if (isLocType)
|
|
return LI->getLoc();
|
|
|
|
// FIXME: Correctly support promotions/truncations.
|
|
ASTContext &Ctx = ValMgr.getContext();
|
|
unsigned castSize = Ctx.getTypeSize(castTy);
|
|
if (castSize == LI->getNumBits())
|
|
return val;
|
|
|
|
return ValMgr.makeLocAsInteger(LI->getLoc(), castSize);
|
|
}
|
|
|
|
if (const SymExpr *se = val.getAsSymbolicExpression()) {
|
|
ASTContext &Ctx = ValMgr.getContext();
|
|
QualType T = Ctx.getCanonicalType(se->getType(Ctx));
|
|
if (T == Ctx.getCanonicalType(castTy))
|
|
return val;
|
|
|
|
// FIXME: Remove this hack when we support symbolic truncation/extension.
|
|
// HACK: If both castTy and T are integers, ignore the cast. This is
|
|
// not a permanent solution. Eventually we want to precisely handle
|
|
// extension/truncation of symbolic integers. This prevents us from losing
|
|
// precision when we assign 'x = y' and 'y' is symbolic and x and y are
|
|
// different integer types.
|
|
if (T->isIntegerType() && castTy->isIntegerType())
|
|
return val;
|
|
|
|
return UnknownVal();
|
|
}
|
|
|
|
if (!isa<nonloc::ConcreteInt>(val))
|
|
return UnknownVal();
|
|
|
|
// Only handle casts from integers to integers.
|
|
if (!isLocType && !castTy->isIntegerType())
|
|
return UnknownVal();
|
|
|
|
llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
|
|
i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
|
|
i.extOrTrunc(ValMgr.getContext().getTypeSize(castTy));
|
|
|
|
if (isLocType)
|
|
return ValMgr.makeIntLocVal(i);
|
|
else
|
|
return ValMgr.makeIntVal(i);
|
|
}
|
|
|
|
SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) {
|
|
|
|
// Casts from pointers -> pointers, just return the lval.
|
|
//
|
|
// Casts from pointers -> references, just return the lval. These
|
|
// can be introduced by the frontend for corner cases, e.g
|
|
// casting from va_list* to __builtin_va_list&.
|
|
//
|
|
if (Loc::IsLocType(castTy) || castTy->isReferenceType())
|
|
return val;
|
|
|
|
// FIXME: Handle transparent unions where a value can be "transparently"
|
|
// lifted into a union type.
|
|
if (castTy->isUnionType())
|
|
return UnknownVal();
|
|
|
|
if (castTy->isIntegerType()) {
|
|
unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
|
|
|
|
if (!isa<loc::ConcreteInt>(val))
|
|
return ValMgr.makeLocAsInteger(val, BitWidth);
|
|
|
|
llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
|
|
i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
|
|
i.extOrTrunc(BitWidth);
|
|
return ValMgr.makeIntVal(i);
|
|
}
|
|
|
|
// All other cases: return 'UnknownVal'. This includes casting pointers
|
|
// to floats, which is probably badness it itself, but this is a good
|
|
// intermediate solution until we do something better.
|
|
return UnknownVal();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Transfer function for unary operators.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SVal SimpleSValuator::EvalMinus(NonLoc val) {
|
|
switch (val.getSubKind()) {
|
|
case nonloc::ConcreteIntKind:
|
|
return cast<nonloc::ConcreteInt>(val).evalMinus(ValMgr);
|
|
default:
|
|
return UnknownVal();
|
|
}
|
|
}
|
|
|
|
SVal SimpleSValuator::EvalComplement(NonLoc X) {
|
|
switch (X.getSubKind()) {
|
|
case nonloc::ConcreteIntKind:
|
|
return cast<nonloc::ConcreteInt>(X).evalComplement(ValMgr);
|
|
default:
|
|
return UnknownVal();
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Transfer function for binary operators.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
|
|
switch (op) {
|
|
default:
|
|
assert(false && "Invalid opcode.");
|
|
case BinaryOperator::LT: return BinaryOperator::GE;
|
|
case BinaryOperator::GT: return BinaryOperator::LE;
|
|
case BinaryOperator::LE: return BinaryOperator::GT;
|
|
case BinaryOperator::GE: return BinaryOperator::LT;
|
|
case BinaryOperator::EQ: return BinaryOperator::NE;
|
|
case BinaryOperator::NE: return BinaryOperator::EQ;
|
|
}
|
|
}
|
|
|
|
static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) {
|
|
switch (op) {
|
|
default:
|
|
assert(false && "Invalid opcode.");
|
|
case BinaryOperator::LT: return BinaryOperator::GT;
|
|
case BinaryOperator::GT: return BinaryOperator::LT;
|
|
case BinaryOperator::LE: return BinaryOperator::GE;
|
|
case BinaryOperator::GE: return BinaryOperator::LE;
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::NE:
|
|
return op;
|
|
}
|
|
}
|
|
|
|
SVal SimpleSValuator::MakeSymIntVal(const SymExpr *LHS,
|
|
BinaryOperator::Opcode op,
|
|
const llvm::APSInt &RHS,
|
|
QualType resultTy) {
|
|
bool isIdempotent = false;
|
|
|
|
// Check for a few special cases with known reductions first.
|
|
switch (op) {
|
|
default:
|
|
// We can't reduce this case; just treat it normally.
|
|
break;
|
|
case BinaryOperator::Mul:
|
|
// a*0 and a*1
|
|
if (RHS == 0)
|
|
return ValMgr.makeIntVal(0, resultTy);
|
|
else if (RHS == 1)
|
|
isIdempotent = true;
|
|
break;
|
|
case BinaryOperator::Div:
|
|
// a/0 and a/1
|
|
if (RHS == 0)
|
|
// This is also handled elsewhere.
|
|
return UndefinedVal();
|
|
else if (RHS == 1)
|
|
isIdempotent = true;
|
|
break;
|
|
case BinaryOperator::Rem:
|
|
// a%0 and a%1
|
|
if (RHS == 0)
|
|
// This is also handled elsewhere.
|
|
return UndefinedVal();
|
|
else if (RHS == 1)
|
|
return ValMgr.makeIntVal(0, resultTy);
|
|
break;
|
|
case BinaryOperator::Add:
|
|
case BinaryOperator::Sub:
|
|
case BinaryOperator::Shl:
|
|
case BinaryOperator::Shr:
|
|
case BinaryOperator::Xor:
|
|
// a+0, a-0, a<<0, a>>0, a^0
|
|
if (RHS == 0)
|
|
isIdempotent = true;
|
|
break;
|
|
case BinaryOperator::And:
|
|
// a&0 and a&(~0)
|
|
if (RHS == 0)
|
|
return ValMgr.makeIntVal(0, resultTy);
|
|
else if (RHS.isAllOnesValue())
|
|
isIdempotent = true;
|
|
break;
|
|
case BinaryOperator::Or:
|
|
// a|0 and a|(~0)
|
|
if (RHS == 0)
|
|
isIdempotent = true;
|
|
else if (RHS.isAllOnesValue()) {
|
|
BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
|
|
const llvm::APSInt &Result = BVF.Convert(resultTy, RHS);
|
|
return nonloc::ConcreteInt(Result);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Idempotent ops (like a*1) can still change the type of an expression.
|
|
// Wrap the LHS up in a NonLoc again and let EvalCastNL do the dirty work.
|
|
if (isIdempotent) {
|
|
if (SymbolRef LHSSym = dyn_cast<SymbolData>(LHS))
|
|
return EvalCastNL(nonloc::SymbolVal(LHSSym), resultTy);
|
|
return EvalCastNL(nonloc::SymExprVal(LHS), resultTy);
|
|
}
|
|
|
|
// If we reach this point, the expression cannot be simplified.
|
|
// Make a SymExprVal for the entire thing.
|
|
return ValMgr.makeNonLoc(LHS, op, RHS, resultTy);
|
|
}
|
|
|
|
SVal SimpleSValuator::EvalBinOpNN(const GRState *state,
|
|
BinaryOperator::Opcode op,
|
|
NonLoc lhs, NonLoc rhs,
|
|
QualType resultTy) {
|
|
// Handle trivial case where left-side and right-side are the same.
|
|
if (lhs == rhs)
|
|
switch (op) {
|
|
default:
|
|
break;
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::LE:
|
|
case BinaryOperator::GE:
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
case BinaryOperator::LT:
|
|
case BinaryOperator::GT:
|
|
case BinaryOperator::NE:
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
case BinaryOperator::Xor:
|
|
case BinaryOperator::Sub:
|
|
return ValMgr.makeIntVal(0, resultTy);
|
|
case BinaryOperator::Or:
|
|
case BinaryOperator::And:
|
|
return EvalCastNL(lhs, resultTy);
|
|
}
|
|
|
|
while (1) {
|
|
switch (lhs.getSubKind()) {
|
|
default:
|
|
return UnknownVal();
|
|
case nonloc::LocAsIntegerKind: {
|
|
Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
|
|
switch (rhs.getSubKind()) {
|
|
case nonloc::LocAsIntegerKind:
|
|
return EvalBinOpLL(state, op, lhsL,
|
|
cast<nonloc::LocAsInteger>(rhs).getLoc(),
|
|
resultTy);
|
|
case nonloc::ConcreteIntKind: {
|
|
// Transform the integer into a location and compare.
|
|
ASTContext& Ctx = ValMgr.getContext();
|
|
llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
|
|
i.setIsUnsigned(true);
|
|
i.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy));
|
|
return EvalBinOpLL(state, op, lhsL, ValMgr.makeLoc(i), resultTy);
|
|
}
|
|
default:
|
|
switch (op) {
|
|
case BinaryOperator::EQ:
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
case BinaryOperator::NE:
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
default:
|
|
// This case also handles pointer arithmetic.
|
|
return UnknownVal();
|
|
}
|
|
}
|
|
}
|
|
case nonloc::SymExprValKind: {
|
|
nonloc::SymExprVal *selhs = cast<nonloc::SymExprVal>(&lhs);
|
|
|
|
// Only handle LHS of the form "$sym op constant", at least for now.
|
|
const SymIntExpr *symIntExpr =
|
|
dyn_cast<SymIntExpr>(selhs->getSymbolicExpression());
|
|
|
|
if (!symIntExpr)
|
|
return UnknownVal();
|
|
|
|
// Is this a logical not? (!x is represented as x == 0.)
|
|
if (op == BinaryOperator::EQ && rhs.isZeroConstant()) {
|
|
// We know how to negate certain expressions. Simplify them here.
|
|
|
|
BinaryOperator::Opcode opc = symIntExpr->getOpcode();
|
|
switch (opc) {
|
|
default:
|
|
// We don't know how to negate this operation.
|
|
// Just handle it as if it were a normal comparison to 0.
|
|
break;
|
|
case BinaryOperator::LAnd:
|
|
case BinaryOperator::LOr:
|
|
assert(false && "Logical operators handled by branching logic.");
|
|
return UnknownVal();
|
|
case BinaryOperator::Assign:
|
|
case BinaryOperator::MulAssign:
|
|
case BinaryOperator::DivAssign:
|
|
case BinaryOperator::RemAssign:
|
|
case BinaryOperator::AddAssign:
|
|
case BinaryOperator::SubAssign:
|
|
case BinaryOperator::ShlAssign:
|
|
case BinaryOperator::ShrAssign:
|
|
case BinaryOperator::AndAssign:
|
|
case BinaryOperator::XorAssign:
|
|
case BinaryOperator::OrAssign:
|
|
case BinaryOperator::Comma:
|
|
assert(false && "'=' and ',' operators handled by GRExprEngine.");
|
|
return UnknownVal();
|
|
case BinaryOperator::PtrMemD:
|
|
case BinaryOperator::PtrMemI:
|
|
assert(false && "Pointer arithmetic not handled here.");
|
|
return UnknownVal();
|
|
case BinaryOperator::LT:
|
|
case BinaryOperator::GT:
|
|
case BinaryOperator::LE:
|
|
case BinaryOperator::GE:
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::NE:
|
|
// Negate the comparison and make a value.
|
|
opc = NegateComparison(opc);
|
|
assert(symIntExpr->getType(ValMgr.getContext()) == resultTy);
|
|
return ValMgr.makeNonLoc(symIntExpr->getLHS(), opc,
|
|
symIntExpr->getRHS(), resultTy);
|
|
}
|
|
}
|
|
|
|
// For now, only handle expressions whose RHS is a constant.
|
|
const nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs);
|
|
if (!rhsInt)
|
|
return UnknownVal();
|
|
|
|
// If both the LHS and the current expression are additive,
|
|
// fold their constants.
|
|
if (BinaryOperator::isAdditiveOp(op)) {
|
|
BinaryOperator::Opcode lop = symIntExpr->getOpcode();
|
|
if (BinaryOperator::isAdditiveOp(lop)) {
|
|
BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
|
|
|
|
// resultTy may not be the best type to convert to, but it's
|
|
// probably the best choice in expressions with mixed type
|
|
// (such as x+1U+2LL). The rules for implicit conversions should
|
|
// choose a reasonable type to preserve the expression, and will
|
|
// at least match how the value is going to be used.
|
|
const llvm::APSInt &first =
|
|
BVF.Convert(resultTy, symIntExpr->getRHS());
|
|
const llvm::APSInt &second =
|
|
BVF.Convert(resultTy, rhsInt->getValue());
|
|
|
|
const llvm::APSInt *newRHS;
|
|
if (lop == op)
|
|
newRHS = BVF.EvaluateAPSInt(BinaryOperator::Add, first, second);
|
|
else
|
|
newRHS = BVF.EvaluateAPSInt(BinaryOperator::Sub, first, second);
|
|
return MakeSymIntVal(symIntExpr->getLHS(), lop, *newRHS, resultTy);
|
|
}
|
|
}
|
|
|
|
// Otherwise, make a SymExprVal out of the expression.
|
|
return MakeSymIntVal(symIntExpr, op, rhsInt->getValue(), resultTy);
|
|
}
|
|
case nonloc::ConcreteIntKind: {
|
|
const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
|
|
|
|
if (isa<nonloc::ConcreteInt>(rhs)) {
|
|
return lhsInt.evalBinOp(ValMgr, op, cast<nonloc::ConcreteInt>(rhs));
|
|
} else {
|
|
const llvm::APSInt& lhsValue = lhsInt.getValue();
|
|
|
|
// Swap the left and right sides and flip the operator if doing so
|
|
// allows us to better reason about the expression (this is a form
|
|
// of expression canonicalization).
|
|
// While we're at it, catch some special cases for non-commutative ops.
|
|
NonLoc tmp = rhs;
|
|
rhs = lhs;
|
|
lhs = tmp;
|
|
|
|
switch (op) {
|
|
case BinaryOperator::LT:
|
|
case BinaryOperator::GT:
|
|
case BinaryOperator::LE:
|
|
case BinaryOperator::GE:
|
|
op = ReverseComparison(op);
|
|
continue;
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::NE:
|
|
case BinaryOperator::Add:
|
|
case BinaryOperator::Mul:
|
|
case BinaryOperator::And:
|
|
case BinaryOperator::Xor:
|
|
case BinaryOperator::Or:
|
|
continue;
|
|
case BinaryOperator::Shr:
|
|
if (lhsValue.isAllOnesValue() && lhsValue.isSigned())
|
|
// At this point lhs and rhs have been swapped.
|
|
return rhs;
|
|
// FALL-THROUGH
|
|
case BinaryOperator::Shl:
|
|
if (lhsValue == 0)
|
|
// At this point lhs and rhs have been swapped.
|
|
return rhs;
|
|
return UnknownVal();
|
|
default:
|
|
return UnknownVal();
|
|
}
|
|
}
|
|
}
|
|
case nonloc::SymbolValKind: {
|
|
nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
|
|
SymbolRef Sym = slhs->getSymbol();
|
|
|
|
// Does the symbol simplify to a constant? If so, "fold" the constant
|
|
// by setting 'lhs' to a ConcreteInt and try again.
|
|
if (Sym->getType(ValMgr.getContext())->isIntegerType())
|
|
if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
|
|
// The symbol evaluates to a constant. If necessary, promote the
|
|
// folded constant (LHS) to the result type.
|
|
BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
|
|
const llvm::APSInt &lhs_I = BVF.Convert(resultTy, *Constant);
|
|
lhs = nonloc::ConcreteInt(lhs_I);
|
|
|
|
// Also promote the RHS (if necessary).
|
|
|
|
// For shifts, it necessary promote the RHS to the result type.
|
|
if (BinaryOperator::isShiftOp(op))
|
|
continue;
|
|
|
|
// Other operators: do an implicit conversion. This shouldn't be
|
|
// necessary once we support truncation/extension of symbolic values.
|
|
if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
|
|
rhs = nonloc::ConcreteInt(BVF.Convert(resultTy, rhs_I->getValue()));
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (isa<nonloc::ConcreteInt>(rhs)) {
|
|
return MakeSymIntVal(slhs->getSymbol(), op,
|
|
cast<nonloc::ConcreteInt>(rhs).getValue(),
|
|
resultTy);
|
|
}
|
|
|
|
return UnknownVal();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// FIXME: all this logic will change if/when we have MemRegion::getLocation().
|
|
SVal SimpleSValuator::EvalBinOpLL(const GRState *state,
|
|
BinaryOperator::Opcode op,
|
|
Loc lhs, Loc rhs,
|
|
QualType resultTy) {
|
|
// Only comparisons and subtractions are valid operations on two pointers.
|
|
// See [C99 6.5.5 through 6.5.14] or [C++0x 5.6 through 5.15].
|
|
// However, if a pointer is casted to an integer, EvalBinOpNN may end up
|
|
// calling this function with another operation (PR7527). We don't attempt to
|
|
// model this for now, but it could be useful, particularly when the
|
|
// "location" is actually an integer value that's been passed through a void*.
|
|
if (!(BinaryOperator::isComparisonOp(op) || op == BinaryOperator::Sub))
|
|
return UnknownVal();
|
|
|
|
// Special cases for when both sides are identical.
|
|
if (lhs == rhs) {
|
|
switch (op) {
|
|
default:
|
|
assert(false && "Unimplemented operation for two identical values");
|
|
return UnknownVal();
|
|
case BinaryOperator::Sub:
|
|
return ValMgr.makeZeroVal(resultTy);
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::LE:
|
|
case BinaryOperator::GE:
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
case BinaryOperator::NE:
|
|
case BinaryOperator::LT:
|
|
case BinaryOperator::GT:
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
}
|
|
}
|
|
|
|
switch (lhs.getSubKind()) {
|
|
default:
|
|
assert(false && "Ordering not implemented for this Loc.");
|
|
return UnknownVal();
|
|
|
|
case loc::GotoLabelKind:
|
|
// The only thing we know about labels is that they're non-null.
|
|
if (rhs.isZeroConstant()) {
|
|
switch (op) {
|
|
default:
|
|
break;
|
|
case BinaryOperator::Sub:
|
|
return EvalCastL(lhs, resultTy);
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::LE:
|
|
case BinaryOperator::LT:
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
case BinaryOperator::NE:
|
|
case BinaryOperator::GT:
|
|
case BinaryOperator::GE:
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
}
|
|
}
|
|
// There may be two labels for the same location, and a function region may
|
|
// have the same address as a label at the start of the function (depending
|
|
// on the ABI).
|
|
// FIXME: we can probably do a comparison against other MemRegions, though.
|
|
// FIXME: is there a way to tell if two labels refer to the same location?
|
|
return UnknownVal();
|
|
|
|
case loc::ConcreteIntKind: {
|
|
// If one of the operands is a symbol and the other is a constant,
|
|
// build an expression for use by the constraint manager.
|
|
if (SymbolRef rSym = rhs.getAsLocSymbol()) {
|
|
// We can only build expressions with symbols on the left,
|
|
// so we need a reversible operator.
|
|
if (!BinaryOperator::isComparisonOp(op))
|
|
return UnknownVal();
|
|
|
|
const llvm::APSInt &lVal = cast<loc::ConcreteInt>(lhs).getValue();
|
|
return ValMgr.makeNonLoc(rSym, ReverseComparison(op), lVal, resultTy);
|
|
}
|
|
|
|
// If both operands are constants, just perform the operation.
|
|
if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
|
|
BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
|
|
SVal ResultVal = cast<loc::ConcreteInt>(lhs).EvalBinOp(BVF, op, *rInt);
|
|
if (Loc *Result = dyn_cast<Loc>(&ResultVal))
|
|
return EvalCastL(*Result, resultTy);
|
|
else
|
|
return UnknownVal();
|
|
}
|
|
|
|
// Special case comparisons against NULL.
|
|
// This must come after the test if the RHS is a symbol, which is used to
|
|
// build constraints. The address of any non-symbolic region is guaranteed
|
|
// to be non-NULL, as is any label.
|
|
assert(isa<loc::MemRegionVal>(rhs) || isa<loc::GotoLabel>(rhs));
|
|
if (lhs.isZeroConstant()) {
|
|
switch (op) {
|
|
default:
|
|
break;
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::GT:
|
|
case BinaryOperator::GE:
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
case BinaryOperator::NE:
|
|
case BinaryOperator::LT:
|
|
case BinaryOperator::LE:
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
}
|
|
}
|
|
|
|
// Comparing an arbitrary integer to a region or label address is
|
|
// completely unknowable.
|
|
return UnknownVal();
|
|
}
|
|
case loc::MemRegionKind: {
|
|
if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
|
|
// If one of the operands is a symbol and the other is a constant,
|
|
// build an expression for use by the constraint manager.
|
|
if (SymbolRef lSym = lhs.getAsLocSymbol())
|
|
return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);
|
|
|
|
// Special case comparisons to NULL.
|
|
// This must come after the test if the LHS is a symbol, which is used to
|
|
// build constraints. The address of any non-symbolic region is guaranteed
|
|
// to be non-NULL.
|
|
if (rInt->isZeroConstant()) {
|
|
switch (op) {
|
|
default:
|
|
break;
|
|
case BinaryOperator::Sub:
|
|
return EvalCastL(lhs, resultTy);
|
|
case BinaryOperator::EQ:
|
|
case BinaryOperator::LT:
|
|
case BinaryOperator::LE:
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
case BinaryOperator::NE:
|
|
case BinaryOperator::GT:
|
|
case BinaryOperator::GE:
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
}
|
|
}
|
|
|
|
// Comparing a region to an arbitrary integer is completely unknowable.
|
|
return UnknownVal();
|
|
}
|
|
|
|
// Get both values as regions, if possible.
|
|
const MemRegion *LeftMR = lhs.getAsRegion();
|
|
assert(LeftMR && "MemRegionKind SVal doesn't have a region!");
|
|
|
|
const MemRegion *RightMR = rhs.getAsRegion();
|
|
if (!RightMR)
|
|
// The RHS is probably a label, which in theory could address a region.
|
|
// FIXME: we can probably make a more useful statement about non-code
|
|
// regions, though.
|
|
return UnknownVal();
|
|
|
|
// If both values wrap regions, see if they're from different base regions.
|
|
const MemRegion *LeftBase = LeftMR->getBaseRegion();
|
|
const MemRegion *RightBase = RightMR->getBaseRegion();
|
|
if (LeftBase != RightBase &&
|
|
!isa<SymbolicRegion>(LeftBase) && !isa<SymbolicRegion>(RightBase)) {
|
|
switch (op) {
|
|
default:
|
|
return UnknownVal();
|
|
case BinaryOperator::EQ:
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
case BinaryOperator::NE:
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
}
|
|
}
|
|
|
|
// The two regions are from the same base region. See if they're both a
|
|
// type of region we know how to compare.
|
|
|
|
// FIXME: If/when there is a getAsRawOffset() for FieldRegions, this
|
|
// ElementRegion path and the FieldRegion path below should be unified.
|
|
if (const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR)) {
|
|
// First see if the right region is also an ElementRegion.
|
|
const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR);
|
|
if (!RightER)
|
|
return UnknownVal();
|
|
|
|
// Next, see if the two ERs have the same super-region and matching types.
|
|
// FIXME: This should do something useful even if the types don't match,
|
|
// though if both indexes are constant the RegionRawOffset path will
|
|
// give the correct answer.
|
|
if (LeftER->getSuperRegion() == RightER->getSuperRegion() &&
|
|
LeftER->getElementType() == RightER->getElementType()) {
|
|
// Get the left index and cast it to the correct type.
|
|
// If the index is unknown or undefined, bail out here.
|
|
SVal LeftIndexVal = LeftER->getIndex();
|
|
NonLoc *LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
|
|
if (!LeftIndex)
|
|
return UnknownVal();
|
|
LeftIndexVal = EvalCastNL(*LeftIndex, resultTy);
|
|
LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
|
|
if (!LeftIndex)
|
|
return UnknownVal();
|
|
|
|
// Do the same for the right index.
|
|
SVal RightIndexVal = RightER->getIndex();
|
|
NonLoc *RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
|
|
if (!RightIndex)
|
|
return UnknownVal();
|
|
RightIndexVal = EvalCastNL(*RightIndex, resultTy);
|
|
RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
|
|
if (!RightIndex)
|
|
return UnknownVal();
|
|
|
|
// Actually perform the operation.
|
|
// EvalBinOpNN expects the two indexes to already be the right type.
|
|
return EvalBinOpNN(state, op, *LeftIndex, *RightIndex, resultTy);
|
|
}
|
|
|
|
// If the element indexes aren't comparable, see if the raw offsets are.
|
|
RegionRawOffset LeftOffset = LeftER->getAsRawOffset();
|
|
RegionRawOffset RightOffset = RightER->getAsRawOffset();
|
|
|
|
if (LeftOffset.getRegion() != NULL &&
|
|
LeftOffset.getRegion() == RightOffset.getRegion()) {
|
|
int64_t left = LeftOffset.getByteOffset();
|
|
int64_t right = RightOffset.getByteOffset();
|
|
|
|
switch (op) {
|
|
default:
|
|
return UnknownVal();
|
|
case BinaryOperator::LT:
|
|
return ValMgr.makeTruthVal(left < right, resultTy);
|
|
case BinaryOperator::GT:
|
|
return ValMgr.makeTruthVal(left > right, resultTy);
|
|
case BinaryOperator::LE:
|
|
return ValMgr.makeTruthVal(left <= right, resultTy);
|
|
case BinaryOperator::GE:
|
|
return ValMgr.makeTruthVal(left >= right, resultTy);
|
|
case BinaryOperator::EQ:
|
|
return ValMgr.makeTruthVal(left == right, resultTy);
|
|
case BinaryOperator::NE:
|
|
return ValMgr.makeTruthVal(left != right, resultTy);
|
|
}
|
|
}
|
|
|
|
// If we get here, we have no way of comparing the ElementRegions.
|
|
return UnknownVal();
|
|
}
|
|
|
|
// See if both regions are fields of the same structure.
|
|
// FIXME: This doesn't handle nesting, inheritance, or Objective-C ivars.
|
|
if (const FieldRegion *LeftFR = dyn_cast<FieldRegion>(LeftMR)) {
|
|
// Only comparisons are meaningful here!
|
|
if (!BinaryOperator::isComparisonOp(op))
|
|
return UnknownVal();
|
|
|
|
// First see if the right region is also a FieldRegion.
|
|
const FieldRegion *RightFR = dyn_cast<FieldRegion>(RightMR);
|
|
if (!RightFR)
|
|
return UnknownVal();
|
|
|
|
// Next, see if the two FRs have the same super-region.
|
|
// FIXME: This doesn't handle casts yet, and simply stripping the casts
|
|
// doesn't help.
|
|
if (LeftFR->getSuperRegion() != RightFR->getSuperRegion())
|
|
return UnknownVal();
|
|
|
|
const FieldDecl *LeftFD = LeftFR->getDecl();
|
|
const FieldDecl *RightFD = RightFR->getDecl();
|
|
const RecordDecl *RD = LeftFD->getParent();
|
|
|
|
// Make sure the two FRs are from the same kind of record. Just in case!
|
|
// FIXME: This is probably where inheritance would be a problem.
|
|
if (RD != RightFD->getParent())
|
|
return UnknownVal();
|
|
|
|
// We know for sure that the two fields are not the same, since that
|
|
// would have given us the same SVal.
|
|
if (op == BinaryOperator::EQ)
|
|
return ValMgr.makeTruthVal(false, resultTy);
|
|
if (op == BinaryOperator::NE)
|
|
return ValMgr.makeTruthVal(true, resultTy);
|
|
|
|
// Iterate through the fields and see which one comes first.
|
|
// [C99 6.7.2.1.13] "Within a structure object, the non-bit-field
|
|
// members and the units in which bit-fields reside have addresses that
|
|
// increase in the order in which they are declared."
|
|
bool leftFirst = (op == BinaryOperator::LT || op == BinaryOperator::LE);
|
|
for (RecordDecl::field_iterator I = RD->field_begin(),
|
|
E = RD->field_end(); I!=E; ++I) {
|
|
if (*I == LeftFD)
|
|
return ValMgr.makeTruthVal(leftFirst, resultTy);
|
|
if (*I == RightFD)
|
|
return ValMgr.makeTruthVal(!leftFirst, resultTy);
|
|
}
|
|
|
|
assert(false && "Fields not found in parent record's definition");
|
|
}
|
|
|
|
// If we get here, we have no way of comparing the regions.
|
|
return UnknownVal();
|
|
}
|
|
}
|
|
}
|
|
|
|
SVal SimpleSValuator::EvalBinOpLN(const GRState *state,
|
|
BinaryOperator::Opcode op,
|
|
Loc lhs, NonLoc rhs, QualType resultTy) {
|
|
// Special case: 'rhs' is an integer that has the same width as a pointer and
|
|
// we are using the integer location in a comparison. Normally this cannot be
|
|
// triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
|
|
// can generate comparisons that trigger this code.
|
|
// FIXME: Are all locations guaranteed to have pointer width?
|
|
if (BinaryOperator::isComparisonOp(op)) {
|
|
if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
|
|
const llvm::APSInt *x = &rhsInt->getValue();
|
|
ASTContext &ctx = ValMgr.getContext();
|
|
if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
|
|
// Convert the signedness of the integer (if necessary).
|
|
if (x->isSigned())
|
|
x = &ValMgr.getBasicValueFactory().getValue(*x, true);
|
|
|
|
return EvalBinOpLL(state, op, lhs, loc::ConcreteInt(*x), resultTy);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Delegate pointer arithmetic to the StoreManager.
|
|
return state->getStateManager().getStoreManager().EvalBinOp(op, lhs,
|
|
rhs, resultTy);
|
|
}
|
|
|
|
const llvm::APSInt *SimpleSValuator::getKnownValue(const GRState *state,
|
|
SVal V) {
|
|
if (V.isUnknownOrUndef())
|
|
return NULL;
|
|
|
|
if (loc::ConcreteInt* X = dyn_cast<loc::ConcreteInt>(&V))
|
|
return &X->getValue();
|
|
|
|
if (nonloc::ConcreteInt* X = dyn_cast<nonloc::ConcreteInt>(&V))
|
|
return &X->getValue();
|
|
|
|
if (SymbolRef Sym = V.getAsSymbol())
|
|
return state->getSymVal(Sym);
|
|
|
|
// FIXME: Add support for SymExprs.
|
|
return NULL;
|
|
}
|