ProgramStateRef SimpleConstraintManager::assumeSymWithinInclusiveRange( ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, bool InRange) { // Get the type used for calculating wraparound. BasicValueFactory &BVF = getBasicVals(); APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType()); llvm::APSInt Adjustment = WraparoundType.getZeroValue(); SymbolRef AdjustedSym = Sym; computeAdjustment(AdjustedSym, Adjustment); // Convert the right-hand side integer as necessary. APSIntType ComparisonType = std::max(WraparoundType, APSIntType(From)); llvm::APSInt ConvertedFrom = ComparisonType.convert(From); llvm::APSInt ConvertedTo = ComparisonType.convert(To); // Prefer unsigned comparisons. if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() && ComparisonType.isUnsigned() && !WraparoundType.isUnsigned()) Adjustment.setIsSigned(false); if (InRange) return assumeSymbolWithinInclusiveRange(State, AdjustedSym, ConvertedFrom, ConvertedTo, Adjustment); return assumeSymbolOutOfInclusiveRange(State, AdjustedSym, ConvertedFrom, ConvertedTo, Adjustment); }
ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef State, const SymExpr *LHS, BinaryOperator::Opcode Op, const llvm::APSInt &Int) { assert(BinaryOperator::isComparisonOp(Op) && "Non-comparison ops should be rewritten as comparisons to zero."); // Get the type used for calculating wraparound. BasicValueFactory &BVF = getBasicVals(); APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType()); // We only handle simple comparisons of the form "$sym == constant" // or "($sym+constant1) == constant2". // The adjustment is "constant1" in the above expression. It's used to // "slide" the solution range around for modular arithmetic. For example, // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to // the subclasses of SimpleConstraintManager to handle the adjustment. SymbolRef Sym = LHS; llvm::APSInt Adjustment = WraparoundType.getZeroValue(); computeAdjustment(Sym, Adjustment); // Convert the right-hand side integer as necessary. APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int)); llvm::APSInt ConvertedInt = ComparisonType.convert(Int); // Prefer unsigned comparisons. if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() && ComparisonType.isUnsigned() && !WraparoundType.isUnsigned()) Adjustment.setIsSigned(false); switch (Op) { default: llvm_unreachable("invalid operation not caught by assertion above"); case BO_EQ: return assumeSymEQ(State, Sym, ConvertedInt, Adjustment); case BO_NE: return assumeSymNE(State, Sym, ConvertedInt, Adjustment); case BO_GT: return assumeSymGT(State, Sym, ConvertedInt, Adjustment); case BO_GE: return assumeSymGE(State, Sym, ConvertedInt, Adjustment); case BO_LT: return assumeSymLT(State, Sym, ConvertedInt, Adjustment); case BO_LE: return assumeSymLE(State, Sym, ConvertedInt, Adjustment); } // end switch }
ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state, const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt& Int) { assert(BinaryOperator::isComparisonOp(op) && "Non-comparison ops should be rewritten as comparisons to zero."); BasicValueFactory &BVF = getBasicVals(); ASTContext &Ctx = BVF.getContext(); // Get the type used for calculating wraparound. APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType(Ctx)); // We only handle simple comparisons of the form "$sym == constant" // or "($sym+constant1) == constant2". // The adjustment is "constant1" in the above expression. It's used to // "slide" the solution range around for modular arithmetic. For example, // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to // the subclasses of SimpleConstraintManager to handle the adjustment. SymbolRef Sym = LHS; llvm::APSInt Adjustment = WraparoundType.getZeroValue(); computeAdjustment(Sym, Adjustment); // Convert the right-hand side integer as necessary. APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int)); llvm::APSInt ConvertedInt = ComparisonType.convert(Int); switch (op) { default: // No logic yet for other operators. assume the constraint is feasible. return state; case BO_EQ: return assumeSymEQ(state, Sym, ConvertedInt, Adjustment); case BO_NE: return assumeSymNE(state, Sym, ConvertedInt, Adjustment); case BO_GT: return assumeSymGT(state, Sym, ConvertedInt, Adjustment); case BO_GE: return assumeSymGE(state, Sym, ConvertedInt, Adjustment); case BO_LT: return assumeSymLT(state, Sym, ConvertedInt, Adjustment); case BO_LE: return assumeSymLE(state, Sym, ConvertedInt, Adjustment); } // end switch }
SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy) { NonLoc InputLHS = lhs; NonLoc InputRHS = rhs; // Handle trivial case where left-side and right-side are the same. if (lhs == rhs) switch (op) { default: break; case BO_EQ: case BO_LE: case BO_GE: return makeTruthVal(true, resultTy); case BO_LT: case BO_GT: case BO_NE: return makeTruthVal(false, resultTy); case BO_Xor: case BO_Sub: if (resultTy->isIntegralOrEnumerationType()) return makeIntVal(0, resultTy); return evalCastFromNonLoc(makeIntVal(0, /*Unsigned=*/false), resultTy); case BO_Or: case BO_And: return evalCastFromNonLoc(lhs, resultTy); } while (1) { switch (lhs.getSubKind()) { default: return makeSymExprValNN(state, op, lhs, rhs, resultTy); case nonloc::PointerToMemberKind: { assert(rhs.getSubKind() == nonloc::PointerToMemberKind && "Both SVals should have pointer-to-member-type"); auto LPTM = lhs.castAs<nonloc::PointerToMember>(), RPTM = rhs.castAs<nonloc::PointerToMember>(); auto LPTMD = LPTM.getPTMData(), RPTMD = RPTM.getPTMData(); switch (op) { case BO_EQ: return makeTruthVal(LPTMD == RPTMD, resultTy); case BO_NE: return makeTruthVal(LPTMD != RPTMD, resultTy); default: return UnknownVal(); } } case nonloc::LocAsIntegerKind: { Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc(); switch (rhs.getSubKind()) { case nonloc::LocAsIntegerKind: return evalBinOpLL(state, op, lhsL, rhs.castAs<nonloc::LocAsInteger>().getLoc(), resultTy); case nonloc::ConcreteIntKind: { // Transform the integer into a location and compare. // FIXME: This only makes sense for comparisons. If we want to, say, // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it, // then pack it back into a LocAsInteger. llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue(); BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i); return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy); } default: switch (op) { case BO_EQ: return makeTruthVal(false, resultTy); case BO_NE: return makeTruthVal(true, resultTy); default: // This case also handles pointer arithmetic. return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); } } } case nonloc::ConcreteIntKind: { llvm::APSInt LHSValue = lhs.castAs<nonloc::ConcreteInt>().getValue(); // If we're dealing with two known constants, just perform the operation. if (const llvm::APSInt *KnownRHSValue = getKnownValue(state, rhs)) { llvm::APSInt RHSValue = *KnownRHSValue; if (BinaryOperator::isComparisonOp(op)) { // We're looking for a type big enough to compare the two values. // FIXME: This is not correct. char + short will result in a promotion // to int. Unfortunately we have lost types by this point. APSIntType CompareType = std::max(APSIntType(LHSValue), APSIntType(RHSValue)); CompareType.apply(LHSValue); CompareType.apply(RHSValue); } else if (!BinaryOperator::isShiftOp(op)) { APSIntType IntType = BasicVals.getAPSIntType(resultTy); IntType.apply(LHSValue); IntType.apply(RHSValue); } const llvm::APSInt *Result = BasicVals.evalAPSInt(op, LHSValue, RHSValue); if (!Result) return UndefinedVal(); return nonloc::ConcreteInt(*Result); } // 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. switch (op) { case BO_LT: case BO_GT: case BO_LE: case BO_GE: op = BinaryOperator::reverseComparisonOp(op); // FALL-THROUGH case BO_EQ: case BO_NE: case BO_Add: case BO_Mul: case BO_And: case BO_Xor: case BO_Or: std::swap(lhs, rhs); continue; case BO_Shr: // (~0)>>a if (LHSValue.isAllOnesValue() && LHSValue.isSigned()) return evalCastFromNonLoc(lhs, resultTy); // FALL-THROUGH case BO_Shl: // 0<<a and 0>>a if (LHSValue == 0) return evalCastFromNonLoc(lhs, resultTy); return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); default: return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); } } case nonloc::SymbolValKind: { // We only handle LHS as simple symbols or SymIntExprs. SymbolRef Sym = lhs.castAs<nonloc::SymbolVal>().getSymbol(); // LHS is a symbolic expression. if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(Sym)) { // Is this a logical not? (!x is represented as x == 0.) if (op == BO_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 BO_LAnd: case BO_LOr: llvm_unreachable("Logical operators handled by branching logic."); case BO_Assign: case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_AddAssign: case BO_SubAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: case BO_Comma: llvm_unreachable("'=' and ',' operators handled by ExprEngine."); case BO_PtrMemD: case BO_PtrMemI: llvm_unreachable("Pointer arithmetic not handled here."); case BO_LT: case BO_GT: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: assert(resultTy->isBooleanType() || resultTy == getConditionType()); assert(symIntExpr->getType()->isBooleanType() || getContext().hasSameUnqualifiedType(symIntExpr->getType(), getConditionType())); // Negate the comparison and make a value. opc = BinaryOperator::negateComparisonOp(opc); return makeNonLoc(symIntExpr->getLHS(), opc, symIntExpr->getRHS(), resultTy); } } // For now, only handle expressions whose RHS is a constant. if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) { // If both the LHS and the current expression are additive, // fold their constants and try again. if (BinaryOperator::isAdditiveOp(op)) { BinaryOperator::Opcode lop = symIntExpr->getOpcode(); if (BinaryOperator::isAdditiveOp(lop)) { // Convert the two constants to a common type, then combine them. // 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. APSIntType IntType = BasicVals.getAPSIntType(resultTy); const llvm::APSInt &first = IntType.convert(symIntExpr->getRHS()); const llvm::APSInt &second = IntType.convert(*RHSValue); const llvm::APSInt *newRHS; if (lop == op) newRHS = BasicVals.evalAPSInt(BO_Add, first, second); else newRHS = BasicVals.evalAPSInt(BO_Sub, first, second); assert(newRHS && "Invalid operation despite common type!"); rhs = nonloc::ConcreteInt(*newRHS); lhs = nonloc::SymbolVal(symIntExpr->getLHS()); op = lop; continue; } } // Otherwise, make a SymIntExpr out of the expression. return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy); } } // Does the symbolic expression simplify to a constant? // If so, "fold" the constant by setting 'lhs' to a ConcreteInt // and try again. ConstraintManager &CMgr = state->getConstraintManager(); if (const llvm::APSInt *Constant = CMgr.getSymVal(state, Sym)) { lhs = nonloc::ConcreteInt(*Constant); continue; } // Is the RHS a constant? if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) return MakeSymIntVal(Sym, op, *RHSValue, resultTy); // Give up -- this is not a symbolic expression we can handle. return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy); } } } }