Пример #1
0
/// Adjusts a return value when the called function's return type does not
/// match the caller's expression type. This can happen when a dynamic call
/// is devirtualized, and the overridding method has a covariant (more specific)
/// return type than the parent's method. For C++ objects, this means we need
/// to add base casts.
static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
                              StoreManager &StoreMgr) {
  // For now, the only adjustments we handle apply only to locations.
  if (!V.getAs<Loc>())
    return V;

  // If the types already match, don't do any unnecessary work.
  ExpectedTy = ExpectedTy.getCanonicalType();
  ActualTy = ActualTy.getCanonicalType();
  if (ExpectedTy == ActualTy)
    return V;

  // No adjustment is needed between Objective-C pointer types.
  if (ExpectedTy->isObjCObjectPointerType() &&
      ActualTy->isObjCObjectPointerType())
    return V;

  // C++ object pointers may need "derived-to-base" casts.
  const CXXRecordDecl *ExpectedClass = ExpectedTy->getPointeeCXXRecordDecl();
  const CXXRecordDecl *ActualClass = ActualTy->getPointeeCXXRecordDecl();
  if (ExpectedClass && ActualClass) {
    CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
                       /*DetectVirtual=*/false);
    if (ActualClass->isDerivedFrom(ExpectedClass, Paths) &&
        !Paths.isAmbiguous(ActualTy->getCanonicalTypeUnqualified())) {
      return StoreMgr.evalDerivedToBase(V, Paths.front());
    }
  }

  // Unfortunately, Objective-C does not enforce that overridden methods have
  // covariant return types, so we can't assert that that never happens.
  // Be safe and return UnknownVal().
  return UnknownVal();
}
Пример #2
0
SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType,
                                     bool IsVirtual) {
  const MemRegion *DerivedReg = Derived.getAsRegion();
  if (!DerivedReg)
    return Derived;

  const CXXRecordDecl *BaseDecl = BaseType->getPointeeCXXRecordDecl();
  if (!BaseDecl)
    BaseDecl = BaseType->getAsCXXRecordDecl();
  assert(BaseDecl && "not a C++ object?");

  if (const auto *AlreadyDerivedReg =
          dyn_cast<CXXDerivedObjectRegion>(DerivedReg)) {
    if (const auto *SR =
            dyn_cast<SymbolicRegion>(AlreadyDerivedReg->getSuperRegion()))
      if (SR->getSymbol()->getType()->getPointeeCXXRecordDecl() == BaseDecl)
        return loc::MemRegionVal(SR);

    DerivedReg = AlreadyDerivedReg->getSuperRegion();
  }

  const MemRegion *BaseReg = MRMgr.getCXXBaseObjectRegion(
      BaseDecl, cast<SubRegion>(DerivedReg), IsVirtual);

  return loc::MemRegionVal(BaseReg);
}
Пример #3
0
const CXXRecordDecl *Utils::recordForMemberCall(CXXMemberCallExpr *call, string &implicitCallee)
{
    implicitCallee.clear();
    Expr *implicitArgument= call->getImplicitObjectArgument();
    if (!implicitArgument) {
        return nullptr;
    }

    Stmt *s = implicitArgument;
    while (s) {
        if (auto declRef = dyn_cast<DeclRefExpr>(s)) {
            if (declRef->getDecl()) {
                implicitCallee = declRef->getDecl()->getNameAsString();
                QualType qt = declRef->getDecl()->getType();
                return qt->getPointeeCXXRecordDecl();
            } else {
                return nullptr;
            }
        } else if (auto thisExpr = dyn_cast<CXXThisExpr>(s)) {
            implicitCallee = "this";
            return thisExpr->getType()->getPointeeCXXRecordDecl();
        } else if (auto memberExpr = dyn_cast<MemberExpr>(s)) {
            auto decl = memberExpr->getMemberDecl();
            if (decl) {
                implicitCallee = decl->getNameAsString();
                QualType qt = decl->getType();
                return qt->getPointeeCXXRecordDecl();
            } else {
                return nullptr;
            }
        }

        s = s->child_begin() == s->child_end() ? nullptr : *(s->child_begin());
    }

    return nullptr;
}
Пример #4
0
SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
  loc::MemRegionVal *DerivedRegVal = dyn_cast<loc::MemRegionVal>(&Derived);
  if (!DerivedRegVal)
    return Derived;

  const CXXRecordDecl *BaseDecl = BaseType->getPointeeCXXRecordDecl();
  if (!BaseDecl)
    BaseDecl = BaseType->getAsCXXRecordDecl();
  assert(BaseDecl && "not a C++ object?");

  const MemRegion *BaseReg =
    MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion());

  return loc::MemRegionVal(BaseReg);
}
Пример #5
0
SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType,
                                     bool IsVirtual) {
  Optional<loc::MemRegionVal> DerivedRegVal =
      Derived.getAs<loc::MemRegionVal>();
  if (!DerivedRegVal)
    return Derived;

  const CXXRecordDecl *BaseDecl = BaseType->getPointeeCXXRecordDecl();
  if (!BaseDecl)
    BaseDecl = BaseType->getAsCXXRecordDecl();
  assert(BaseDecl && "not a C++ object?");

  const MemRegion *BaseReg =
    MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion(),
                                 IsVirtual);

  return loc::MemRegionVal(BaseReg);
}
Пример #6
0
static bool regionMatchesCXXRecordType(SVal V, QualType Ty) {
  const MemRegion *MR = V.getAsRegion();
  if (!MR)
    return true;

  const auto *TVR = dyn_cast<TypedValueRegion>(MR);
  if (!TVR)
    return true;

  const CXXRecordDecl *RD = TVR->getValueType()->getAsCXXRecordDecl();
  if (!RD)
    return true;

  const CXXRecordDecl *Expected = Ty->getPointeeCXXRecordDecl();
  if (!Expected)
    Expected = Ty->getAsCXXRecordDecl();

  return Expected->getCanonicalDecl() == RD->getCanonicalDecl();
}
Пример #7
0
SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType,
                                   bool &Failed) {
  Failed = false;

  const MemRegion *MR = Base.getAsRegion();
  if (!MR)
    return UnknownVal();

  // Assume the derived class is a pointer or a reference to a CXX record.
  TargetType = TargetType->getPointeeType();
  assert(!TargetType.isNull());
  const CXXRecordDecl *TargetClass = TargetType->getAsCXXRecordDecl();
  if (!TargetClass && !TargetType->isVoidType())
    return UnknownVal();

  // Drill down the CXXBaseObject chains, which represent upcasts (casts from
  // derived to base).
  while (const CXXRecordDecl *MRClass = getCXXRecordType(MR)) {
    // If found the derived class, the cast succeeds.
    if (MRClass == TargetClass)
      return loc::MemRegionVal(MR);

    // We skip over incomplete types. They must be the result of an earlier
    // reinterpret_cast, as one can only dynamic_cast between types in the same
    // class hierarchy.
    if (!TargetType->isVoidType() && MRClass->hasDefinition()) {
      // Static upcasts are marked as DerivedToBase casts by Sema, so this will
      // only happen when multiple or virtual inheritance is involved.
      CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
                         /*DetectVirtual=*/false);
      if (MRClass->isDerivedFrom(TargetClass, Paths))
        return evalDerivedToBase(loc::MemRegionVal(MR), Paths.front());
    }

    if (const auto *BaseR = dyn_cast<CXXBaseObjectRegion>(MR)) {
      // Drill down the chain to get the derived classes.
      MR = BaseR->getSuperRegion();
      continue;
    }

    // If this is a cast to void*, return the region.
    if (TargetType->isVoidType())
      return loc::MemRegionVal(MR);

    // Strange use of reinterpret_cast can give us paths we don't reason
    // about well, by putting in ElementRegions where we'd expect
    // CXXBaseObjectRegions. If it's a valid reinterpret_cast (i.e. if the
    // derived class has a zero offset from the base class), then it's safe
    // to strip the cast; if it's invalid, -Wreinterpret-base-class should
    // catch it. In the interest of performance, the analyzer will silently
    // do the wrong thing in the invalid case (because offsets for subregions
    // will be wrong).
    const MemRegion *Uncasted = MR->StripCasts(/*IncludeBaseCasts=*/false);
    if (Uncasted == MR) {
      // We reached the bottom of the hierarchy and did not find the derived
      // class. We must be casting the base to derived, so the cast should
      // fail.
      break;
    }

    MR = Uncasted;
  }

  // If we're casting a symbolic base pointer to a derived class, use
  // CXXDerivedObjectRegion to represent the cast. If it's a pointer to an
  // unrelated type, it must be a weird reinterpret_cast and we have to
  // be fine with ElementRegion. TODO: Should we instead make
  // Derived{TargetClass, Element{SourceClass, SR}}?
  if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
    QualType T = SR->getSymbol()->getType();
    const CXXRecordDecl *SourceClass = T->getPointeeCXXRecordDecl();
    if (TargetClass && SourceClass && TargetClass->isDerivedFrom(SourceClass))
      return loc::MemRegionVal(
          MRMgr.getCXXDerivedObjectRegion(TargetClass, SR));
    return loc::MemRegionVal(GetElementZeroRegion(SR, TargetType));
  }

  // We failed if the region we ended up with has perfect type info.
  Failed = isa<TypedValueRegion>(MR);
  return UnknownVal();
}
void ProTypeCstyleCastCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *MatchedCast = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");

  if (MatchedCast->getCastKind() == CK_BitCast ||
      MatchedCast->getCastKind() == CK_LValueBitCast ||
      MatchedCast->getCastKind() == CK_IntegralToPointer ||
      MatchedCast->getCastKind() == CK_PointerToIntegral ||
      MatchedCast->getCastKind() == CK_ReinterpretMemberPointer) {
    diag(MatchedCast->getLocStart(),
         "do not use C-style cast to convert between unrelated types");
    return;
  }

  QualType SourceType = MatchedCast->getSubExpr()->getType();

  if (MatchedCast->getCastKind() == CK_BaseToDerived) {
    const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl();
    if (!SourceDecl) // The cast is from object to reference.
      SourceDecl = SourceType->getAsCXXRecordDecl();
    if (!SourceDecl)
      return;

    if (SourceDecl->isPolymorphic()) {
      // Leave type spelling exactly as it was (unlike
      // getTypeAsWritten().getAsString() which would spell enum types 'enum
      // X').
      StringRef DestTypeString = Lexer::getSourceText(
          CharSourceRange::getTokenRange(
              MatchedCast->getLParenLoc().getLocWithOffset(1),
              MatchedCast->getRParenLoc().getLocWithOffset(-1)),
          *Result.SourceManager, getLangOpts());

      auto diag_builder = diag(
          MatchedCast->getLocStart(),
          "do not use C-style cast to downcast from a base to a derived class; "
          "use dynamic_cast instead");

      const Expr *SubExpr =
          MatchedCast->getSubExprAsWritten()->IgnoreImpCasts();
      std::string CastText = ("dynamic_cast<" + DestTypeString + ">").str();
      if (!isa<ParenExpr>(SubExpr)) {
        CastText.push_back('(');
        diag_builder << FixItHint::CreateInsertion(
            Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0,
                                       *Result.SourceManager, getLangOpts()),
            ")");
      }
      auto ParenRange = CharSourceRange::getTokenRange(
          MatchedCast->getLParenLoc(), MatchedCast->getRParenLoc());
      diag_builder << FixItHint::CreateReplacement(ParenRange, CastText);
    } else {
      diag(
          MatchedCast->getLocStart(),
          "do not use C-style cast to downcast from a base to a derived class");
    }
    return;
  }

  if (MatchedCast->getCastKind() == CK_NoOp &&
      needsConstCast(SourceType, MatchedCast->getType())) {
    diag(MatchedCast->getLocStart(),
         "do not use C-style cast to cast away constness");
  }
}
Пример #9
0
static bool isOSObjectPtr(QualType QT) {
  return isOSObjectSubclass(QT->getPointeeCXXRecordDecl());
}