Пример #1
0
FlatStoreManager::RegionInterval
FlatStoreManager::RegionToInterval(const MemRegion *R) {
    switch (R->getKind()) {
    case MemRegion::VarRegionKind: {
        QualType T = cast<VarRegion>(R)->getValueType();
        int64_t Size = Ctx.getTypeSize(T);
        return RegionInterval(R, 0, Size-1);
    }

    case MemRegion::ElementRegionKind:
    case MemRegion::FieldRegionKind: {
        RegionOffset Offset = R->getAsOffset();
        // We cannot compute offset for all regions, for example, elements
        // with symbolic offsets.
        if (!Offset.getRegion())
            return RegionInterval(0, 0, 0);
        int64_t Start = Offset.getOffset();
        int64_t Size = Ctx.getTypeSize(cast<TypedRegion>(R)->getValueType());
        return RegionInterval(Offset.getRegion(), Start, Start+Size);
    }

    default:
        llvm_unreachable("Region kind unhandled.");
        return RegionInterval(0, 0, 0);
    }
}
Пример #2
0
// FIXME: all this logic will change if/when we have MemRegion::getLocation().
SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef 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 == BO_Sub))
    return UnknownVal();

  // Special cases for when both sides are identical.
  if (lhs == rhs) {
    switch (op) {
    default:
      llvm_unreachable("Unimplemented operation for two identical values");
    case BO_Sub:
      return makeZeroVal(resultTy);
    case BO_EQ:
    case BO_LE:
    case BO_GE:
      return makeTruthVal(true, resultTy);
    case BO_NE:
    case BO_LT:
    case BO_GT:
      return makeTruthVal(false, resultTy);
    }
  }

  switch (lhs.getSubKind()) {
  default:
    llvm_unreachable("Ordering not implemented for this Loc.");

  case loc::GotoLabelKind:
    // The only thing we know about labels is that they're non-null.
    if (rhs.isZeroConstant()) {
      switch (op) {
      default:
        break;
      case BO_Sub:
        return evalCastFromLoc(lhs, resultTy);
      case BO_EQ:
      case BO_LE:
      case BO_LT:
        return makeTruthVal(false, resultTy);
      case BO_NE:
      case BO_GT:
      case BO_GE:
        return 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 = lhs.castAs<loc::ConcreteInt>().getValue();
      op = BinaryOperator::reverseComparisonOp(op);
      return makeNonLoc(rSym, op, lVal, resultTy);
    }

    // If both operands are constants, just perform the operation.
    if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
      SVal ResultVal =
          lhs.castAs<loc::ConcreteInt>().evalBinOp(BasicVals, op, *rInt);
      if (Optional<NonLoc> Result = ResultVal.getAs<NonLoc>())
        return evalCastFromNonLoc(*Result, resultTy);

      assert(!ResultVal.getAs<Loc>() && "Loc-Loc ops should not produce Locs");
      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(rhs.getAs<loc::MemRegionVal>() || rhs.getAs<loc::GotoLabel>());
    if (lhs.isZeroConstant()) {
      switch (op) {
      default:
        break;
      case BO_EQ:
      case BO_GT:
      case BO_GE:
        return makeTruthVal(false, resultTy);
      case BO_NE:
      case BO_LT:
      case BO_LE:
        return makeTruthVal(true, resultTy);
      }
    }

    // Comparing an arbitrary integer to a region or label address is
    // completely unknowable.
    return UnknownVal();
  }
  case loc::MemRegionValKind: {
    if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
      // 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(true))
        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()) {
        if (op == BO_Sub)
          return evalCastFromLoc(lhs, resultTy);

        if (BinaryOperator::isComparisonOp(op)) {
          QualType boolType = getContext().BoolTy;
          NonLoc l = evalCastFromLoc(lhs, boolType).castAs<NonLoc>();
          NonLoc r = makeTruthVal(false, boolType).castAs<NonLoc>();
          return evalBinOpNN(state, op, l, r, 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 && "MemRegionValKind 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();

    const MemRegion *LeftBase = LeftMR->getBaseRegion();
    const MemRegion *RightBase = RightMR->getBaseRegion();
    const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace();
    const MemSpaceRegion *RightMS = RightBase->getMemorySpace();
    const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();

    // If the two regions are from different known memory spaces they cannot be
    // equal. Also, assume that no symbolic region (whose memory space is
    // unknown) is on the stack.
    if (LeftMS != RightMS &&
        ((LeftMS != UnknownMS && RightMS != UnknownMS) ||
         (isa<StackSpaceRegion>(LeftMS) || isa<StackSpaceRegion>(RightMS)))) {
      switch (op) {
      default:
        return UnknownVal();
      case BO_EQ:
        return makeTruthVal(false, resultTy);
      case BO_NE:
        return makeTruthVal(true, resultTy);
      }
    }

    // If both values wrap regions, see if they're from different base regions.
    // Note, heap base symbolic regions are assumed to not alias with
    // each other; for example, we assume that malloc returns different address
    // on each invocation.
    // FIXME: ObjC object pointers always reside on the heap, but currently
    // we treat their memory space as unknown, because symbolic pointers
    // to ObjC objects may alias. There should be a way to construct
    // possibly-aliasing heap-based regions. For instance, MacOSXApiChecker
    // guesses memory space for ObjC object pointers manually instead of
    // relying on us.
    if (LeftBase != RightBase &&
        ((!isa<SymbolicRegion>(LeftBase) && !isa<SymbolicRegion>(RightBase)) ||
         (isa<HeapSpaceRegion>(LeftMS) || isa<HeapSpaceRegion>(RightMS))) ){
      switch (op) {
      default:
        return UnknownVal();
      case BO_EQ:
        return makeTruthVal(false, resultTy);
      case BO_NE:
        return makeTruthVal(true, resultTy);
      }
    }

    // Handle special cases for when both regions are element regions.
    const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR);
    const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR);
    if (RightER && LeftER) {
      // 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();
        Optional<NonLoc> LeftIndex = LeftIndexVal.getAs<NonLoc>();
        if (!LeftIndex)
          return UnknownVal();
        LeftIndexVal = evalCastFromNonLoc(*LeftIndex, ArrayIndexTy);
        LeftIndex = LeftIndexVal.getAs<NonLoc>();
        if (!LeftIndex)
          return UnknownVal();

        // Do the same for the right index.
        SVal RightIndexVal = RightER->getIndex();
        Optional<NonLoc> RightIndex = RightIndexVal.getAs<NonLoc>();
        if (!RightIndex)
          return UnknownVal();
        RightIndexVal = evalCastFromNonLoc(*RightIndex, ArrayIndexTy);
        RightIndex = RightIndexVal.getAs<NonLoc>();
        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);
      }
    }

    // Special handling of the FieldRegions, even with symbolic offsets.
    const FieldRegion *RightFR = dyn_cast<FieldRegion>(RightMR);
    const FieldRegion *LeftFR = dyn_cast<FieldRegion>(LeftMR);
    if (RightFR && LeftFR) {
      SVal R = evalBinOpFieldRegionFieldRegion(LeftFR, RightFR, op, resultTy,
                                               *this);
      if (!R.isUnknown())
        return R;
    }

    // Compare the regions using the raw offsets.
    RegionOffset LeftOffset = LeftMR->getAsOffset();
    RegionOffset RightOffset = RightMR->getAsOffset();

    if (LeftOffset.getRegion() != nullptr &&
        LeftOffset.getRegion() == RightOffset.getRegion() &&
        !LeftOffset.hasSymbolicOffset() && !RightOffset.hasSymbolicOffset()) {
      int64_t left = LeftOffset.getOffset();
      int64_t right = RightOffset.getOffset();

      switch (op) {
        default:
          return UnknownVal();
        case BO_LT:
          return makeTruthVal(left < right, resultTy);
        case BO_GT:
          return makeTruthVal(left > right, resultTy);
        case BO_LE:
          return makeTruthVal(left <= right, resultTy);
        case BO_GE:
          return makeTruthVal(left >= right, resultTy);
        case BO_EQ:
          return makeTruthVal(left == right, resultTy);
        case BO_NE:
          return makeTruthVal(left != right, resultTy);
      }
    }

    // At this point we're not going to get a good answer, but we can try
    // conjuring an expression instead.
    SymbolRef LHSSym = lhs.getAsLocSymbol();
    SymbolRef RHSSym = rhs.getAsLocSymbol();
    if (LHSSym && RHSSym)
      return makeNonLoc(LHSSym, op, RHSSym, resultTy);

    // If we get here, we have no way of comparing the regions.
    return UnknownVal();
  }
  }
}