Пример #1
0
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
///  implicit casts that arise from loads from regions that are reinterpreted
///  as another region.
SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
                                    QualType castTy) {
  if (castTy.isNull() || V.isUnknownOrUndef())
    return V;

  // The dispatchCast() call below would convert the int into a float.
  // What we want, however, is a bit-by-bit reinterpretation of the int
  // as a float, which usually yields nothing garbage. For now skip casts
  // from ints to floats.
  // TODO: What other combinations of types are affected?
  if (castTy->isFloatingType()) {
    SymbolRef Sym = V.getAsSymbol();
    if (Sym && !Sym->getType()->isFloatingType())
      return UnknownVal();
  }

  // When retrieving symbolic pointer and expecting a non-void pointer,
  // wrap them into element regions of the expected type if necessary.
  // SValBuilder::dispatchCast() doesn't do that, but it is necessary to
  // make sure that the retrieved value makes sense, because there's no other
  // cast in the AST that would tell us to cast it to the correct pointer type.
  // We might need to do that for non-void pointers as well.
  // FIXME: We really need a single good function to perform casts for us
  // correctly every time we need it.
  if (castTy->isPointerType() && !castTy->isVoidPointerType())
    if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion()))
      if (SR->getSymbol()->getType().getCanonicalType() !=
          castTy.getCanonicalType())
        return loc::MemRegionVal(castRegion(SR, castTy));

  return svalBuilder.dispatchCast(V, castTy);
}
Пример #2
0
bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
                                          QualType DestType,
                                          CheckerContext &C) const {
  // Don't warn about explicit loss of precision.
  if (Cast->isEvaluatable(C.getASTContext()))
    return false;

  QualType SubType = Cast->IgnoreParenImpCasts()->getType();

  if (!DestType->isRealType() || !SubType->isIntegerType())
    return false;

  const bool isFloat = DestType->isFloatingType();

  const auto &AC = C.getASTContext();

  // We will find the largest RepresentsUntilExp value such that the DestType
  // can exactly represent all nonnegative integers below 2^RepresentsUntilExp.
  unsigned RepresentsUntilExp;

  if (isFloat) {
    const llvm::fltSemantics &Sema = AC.getFloatTypeSemantics(DestType);
    RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
  } else {
    RepresentsUntilExp = AC.getIntWidth(DestType);
    if (RepresentsUntilExp == 1) {
      // This is just casting a number to bool, probably not a bug.
      return false;
    }
    if (DestType->isSignedIntegerType())
      RepresentsUntilExp--;
  }

  if (RepresentsUntilExp >= sizeof(unsigned long long) * CHAR_BIT) {
    // Avoid overflow in our later calculations.
    return false;
  }

  unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
  if (SubType->isSignedIntegerType())
    CorrectedSrcWidth--;

  if (RepresentsUntilExp >= CorrectedSrcWidth) {
    // Simple case: the destination can store all values of the source type.
    return false;
  }

  unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
  if (isFloat) {
    // If this is a floating point type, it can also represent MaxVal exactly.
    MaxVal++;
  }
  return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
  // TODO: maybe also check negative values with too large magnitude.
}
  Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) {
    if (!m_gClingVD)
      FindAndCacheRuntimeDecls();

    // Build a reference to gCling
    ExprResult gClingDRE
      = m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy,
                                 VK_RValue, SourceLocation());
    // We have the wrapper as Sema's CurContext
    FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext);

    ExprWithCleanups* Cleanups = 0;
    // In case of ExprWithCleanups we need to extend its 'scope' to the call.
    if (E && isa<ExprWithCleanups>(E)) {
      Cleanups = cast<ExprWithCleanups>(E);
      E = Cleanups->getSubExpr();
    }

    // Build a reference to Value* in the wrapper, should be
    // the only argument of the wrapper.
    SourceLocation locStart = (E) ? E->getLocStart() : FD->getLocStart();
    SourceLocation locEnd = (E) ? E->getLocEnd() : FD->getLocEnd();
    ExprResult wrapperSVRDRE
      = m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy,
                                 VK_RValue, locStart);
    QualType ETy = (E) ? E->getType() : m_Context->VoidTy;
    QualType desugaredTy = ETy.getDesugaredType(*m_Context);

    // The expr result is transported as reference, pointer, array, float etc
    // based on the desugared type. We should still expose the typedef'ed
    // (sugared) type to the cling::Value.
    if (desugaredTy->isRecordType() && E->getValueKind() == VK_LValue) {
      // returning a lvalue (not a temporary): the value should contain
      // a reference to the lvalue instead of copying it.
      desugaredTy = m_Context->getLValueReferenceType(desugaredTy);
      ETy = m_Context->getLValueReferenceType(ETy);
    }
    Expr* ETyVP
      = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
                                             (uint64_t)ETy.getAsOpaquePtr());
    Expr* ETransaction
      = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
                                             (uint64_t)getTransaction());

    llvm::SmallVector<Expr*, 6> CallArgs;
    CallArgs.push_back(gClingDRE.take());
    CallArgs.push_back(wrapperSVRDRE.take());
    CallArgs.push_back(ETyVP);
    CallArgs.push_back(ETransaction);

    ExprResult Call;
    SourceLocation noLoc;
    if (desugaredTy->isVoidType()) {
      // In cases where the cling::Value gets reused we need to reset the
      // previous settings to void.
      // We need to synthesize setValueNoAlloc(...), E, because we still need
      // to run E.

      // FIXME: Suboptimal: this discards the already created AST nodes.
      QualType vpQT = m_Context->VoidPtrTy;
      QualType vQT = m_Context->VoidTy;
      Expr* vpQTVP
        = utils::Synthesize::CStyleCastPtrExpr(m_Sema, vpQT,
                                               (uint64_t)vQT.getAsOpaquePtr());
      CallArgs[2] = vpQTVP;


      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   locStart, CallArgs, locEnd);

      if (E)
        Call = m_Sema->CreateBuiltinBinOp(locStart, BO_Comma, Call.take(), E);

    }
    else if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType()){
      // 2) object types :
      // check existance of copy constructor before call
      if (!availableCopyConstructor(desugaredTy, m_Sema))
        return E;
      // call new (setValueWithAlloc(gCling, &SVR, ETy)) (E)
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc,
                                   locStart, CallArgs, locEnd);
      Expr* placement = Call.take();
      if (const ConstantArrayType* constArray
          = dyn_cast<ConstantArrayType>(desugaredTy.getTypePtr())) {
        CallArgs.clear();
        CallArgs.push_back(E);
        CallArgs.push_back(placement);
        uint64_t arrSize
          = m_Context->getConstantArrayElementCount(constArray);
        Expr* arrSizeExpr
          = utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize);

        CallArgs.push_back(arrSizeExpr);
        // 2.1) arrays:
        // call copyArray(T* src, void* placement, int size)
        Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray,
                                     locStart, CallArgs, locEnd);

      }
      else {
        TypeSourceInfo* ETSI
          = m_Context->getTrivialTypeSourceInfo(ETy, noLoc);

        Call = m_Sema->BuildCXXNew(E->getSourceRange(),
                                   /*useGlobal ::*/true,
                                   /*placementLParen*/ noLoc,
                                   MultiExprArg(placement),
                                   /*placementRParen*/ noLoc,
                                   /*TypeIdParens*/ SourceRange(),
                                   /*allocType*/ ETSI->getType(),
                                   /*allocTypeInfo*/ETSI,
                                   /*arraySize*/0,
                                   /*directInitRange*/E->getSourceRange(),
                                   /*initializer*/E,
                                   /*mayContainAuto*/false
                                   );
      }
    }
    else if (desugaredTy->isIntegralOrEnumerationType()
             || desugaredTy->isReferenceType()
             || desugaredTy->isPointerType()
             || desugaredTy->isFloatingType()) {
      if (desugaredTy->isIntegralOrEnumerationType()) {
        // 1)  enum, integral, float, double, referece, pointer types :
        //      call to cling::internal::setValueNoAlloc(...);

        // If the type is enum or integral we need to force-cast it into
        // uint64 in order to pick up the correct overload.
        if (desugaredTy->isIntegralOrEnumerationType()) {
          QualType UInt64Ty = m_Context->UnsignedLongLongTy;
          TypeSourceInfo* TSI
            = m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc);
          Expr* castedE
            = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
          CallArgs.push_back(castedE);
        }
      }
      else if (desugaredTy->isReferenceType()) {
        // we need to get the address of the references
        Expr* AddrOfE = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf,
                                             E).take();
        CallArgs.push_back(AddrOfE);
      }
      else if (desugaredTy->isPointerType()) {
        // function pointers need explicit void* cast.
        QualType VoidPtrTy = m_Context->VoidPtrTy;
        TypeSourceInfo* TSI
          = m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc);
        Expr* castedE
          = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
        CallArgs.push_back(castedE);
      }
      else if (desugaredTy->isFloatingType()) {
        // floats and double will fall naturally in the correct
        // case, because of the overload resolution.
        CallArgs.push_back(E);
      }
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   locStart, CallArgs, locEnd);
    }
    else
      assert(0 && "Unhandled code path?");

    assert(!Call.isInvalid() && "Invalid Call");

    // Extend the scope of the temporary cleaner if applicable.
    if (Cleanups) {
      Cleanups->setSubExpr(Call.take());
      Cleanups->setValueKind(Call.take()->getValueKind());
      Cleanups->setType(Call.take()->getType());
      return Cleanups;
    }
    return Call.take();
  }
Пример #4
0
 void ICEVisitor::VisitBinaryOperator(BinaryOperator *BO) {
   const NamedDecl *ACD = dyn_cast_or_null<NamedDecl>(AC->getDecl());
   VisitChildren(BO);
   std::string ename = "EventNumber_t";
   clang::Expr *LHS = BO->getLHS();
   clang::Expr *RHS = BO->getRHS();
   if (!LHS || !RHS)
     return;
   std::string lname = LHS->getType().getAsString();
   std::string rname = RHS->getType().getAsString();
   if (IntegerLiteral::classof(LHS->IgnoreCasts()) || IntegerLiteral::classof(RHS->IgnoreCasts()))
     return;
   if (!(lname == ename || rname == ename))
     return;
   if (lname == ename && rname == ename)
     return;
   clang::QualType OTy;
   clang::QualType TTy;
   if (lname == ename && ImplicitCastExpr::classof(RHS)) {
     ImplicitCastExpr *ICE = dyn_cast_or_null<ImplicitCastExpr>(RHS);
     TTy = BR.getContext().getCanonicalType(LHS->getType());
     OTy = BR.getContext().getCanonicalType(ICE->getSubExprAsWritten()->getType());
   }
   if (rname == ename && ImplicitCastExpr::classof(LHS)) {
     ImplicitCastExpr *ICE = dyn_cast_or_null<ImplicitCastExpr>(LHS);
     TTy = BR.getContext().getCanonicalType(RHS->getType());
     OTy = BR.getContext().getCanonicalType(ICE->getSubExprAsWritten()->getType());
   }
   if (TTy.isNull() || OTy.isNull())
     return;
   QualType ToTy = TTy.getUnqualifiedType();
   QualType OrigTy = OTy.getUnqualifiedType();
   if (!(ToTy->isIntegerType() || ToTy->isFloatingType()))
     return;
   if (ToTy->isBooleanType())
     return;
   CharUnits size_otype = BR.getContext().getTypeSizeInChars(OrigTy);
   CharUnits size_ttype = BR.getContext().getTypeSizeInChars(ToTy);
   std::string oname = OrigTy.getAsString();
   std::string tname = ToTy.getAsString();
   if (ToTy->isFloatingType()) {
     llvm::SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
     os << "Cast-to type, " << tname << ". Cast-from type, " << oname << " . " << support::getQualifiedName(*(ACD));
     clang::ento::PathDiagnosticLocation CELoc =
         clang::ento::PathDiagnosticLocation::createBegin(BO, BR.getSourceManager(), AC);
     BR.EmitBasicReport(ACD,
                        CheckName(),
                        "implicit cast of int type to float type",
                        "CMS code rules",
                        os.str(),
                        CELoc,
                        BO->getSourceRange());
   }
   if ((size_otype > size_ttype)) {
     llvm::SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
     os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Cast may result in truncation. "
        << support::getQualifiedName(*(ACD));
     clang::ento::PathDiagnosticLocation CELoc =
         clang::ento::PathDiagnosticLocation::createBegin(BO, BR.getSourceManager(), AC);
     BR.EmitBasicReport(ACD,
                        CheckName(),
                        "implicit cast of int type to smaller int type could truncate",
                        "CMS code rules",
                        os.str(),
                        CELoc,
                        BO->getSourceRange());
   }
   if ((size_otype == size_ttype) &&
       (ToTy->hasSignedIntegerRepresentation() && OrigTy->hasUnsignedIntegerRepresentation() ||
        ToTy->hasUnsignedIntegerRepresentation() && OrigTy->hasSignedIntegerRepresentation())) {
     llvm::SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
     os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Changes int sign type. "
        << support::getQualifiedName(*(ACD));
     clang::ento::PathDiagnosticLocation CELoc =
         clang::ento::PathDiagnosticLocation::createBegin(BO, BR.getSourceManager(), AC);
     BR.EmitBasicReport(
         ACD, CheckName(), "implicit cast ins sign type", "CMS code rules", os.str(), CELoc, BO->getSourceRange());
   }
   return;
   return;
 }
Пример #5
0
 void ICEVisitor::VisitImplicitCastExpr(ImplicitCastExpr *CE) {
   const NamedDecl *ACD = dyn_cast<NamedDecl>(AC->getDecl());
   VisitChildren(CE);
   const Expr *SE = CE->getSubExprAsWritten();
   std::string sename = SE->getType().getAsString();
   const clang::Expr *E = CE->getSubExpr();
   if (!(sename == "EventNumber_t"))
     return;
   QualType OTy = BR.getContext().getCanonicalType(E->getType());
   QualType TTy = BR.getContext().getCanonicalType(CE->getType());
   QualType ToTy = TTy.getUnqualifiedType();
   QualType OrigTy = OTy.getUnqualifiedType();
   if (!(ToTy->isIntegerType() || ToTy->isFloatingType()))
     return;
   if (ToTy->isBooleanType())
     return;
   CharUnits size_otype = BR.getContext().getTypeSizeInChars(OrigTy);
   CharUnits size_ttype = BR.getContext().getTypeSizeInChars(ToTy);
   std::string oname = OrigTy.getAsString();
   std::string tname = ToTy.getAsString();
   if (ToTy->isFloatingType()) {
     llvm::SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
     os << "Cast-to type, " << tname << ". Cast-from type, " << oname << " . " << support::getQualifiedName(*(ACD));
     clang::ento::PathDiagnosticLocation CELoc =
         clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
     BR.EmitBasicReport(ACD,
                        CheckName(),
                        "implicit cast of int type to float type",
                        "CMS code rules",
                        os.str(),
                        CELoc,
                        CE->getSourceRange());
   }
   if ((size_otype > size_ttype)) {
     llvm::SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
     os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Cast may result in truncation. "
        << support::getQualifiedName(*(ACD));
     clang::ento::PathDiagnosticLocation CELoc =
         clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
     BR.EmitBasicReport(ACD,
                        CheckName(),
                        "implicit cast of int type to smaller int type could truncate",
                        "CMS code rules",
                        os.str(),
                        CELoc,
                        CE->getSourceRange());
   }
   if (ToTy->hasSignedIntegerRepresentation() && OrigTy->hasUnsignedIntegerRepresentation() ||
       ToTy->hasUnsignedIntegerRepresentation() && OrigTy->hasSignedIntegerRepresentation()) {
     llvm::SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
     os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Changes int sign type. "
        << support::getQualifiedName(*(ACD));
     clang::ento::PathDiagnosticLocation CELoc =
         clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
     BR.EmitBasicReport(ACD,
                        CheckName(),
                        "implicit cast changes int sign type",
                        "CMS code rules",
                        os.str(),
                        CELoc,
                        CE->getSourceRange());
   }
   return;
 }
Пример #6
0
// FIXME: should rewrite according to the cast kind.
SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
  if (val.isUnknownOrUndef() || castTy == originalTy)
    return val;

  // For const casts, just propagate the value.
  if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
    if (Context.hasSameUnqualifiedType(castTy, originalTy))
      return val;

  // Check for casts to real or complex numbers.  We don't handle these at all
  // right now.
  if (castTy->isFloatingType() || castTy->isAnyComplexType())
    return UnknownVal();
  
  // Check for casts from integers to integers.
  if (castTy->isIntegerType() && originalTy->isIntegerType())
    return evalCastNL(cast<NonLoc>(val), castTy);

  // Check for casts from pointers to integers.
  if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
    return evalCastL(cast<Loc>(val), castTy);

  // Check for casts from integers to pointers.
  if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
    if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
      if (const MemRegion *R = LV->getLoc().getAsRegion()) {
        StoreManager &storeMgr = StateMgr.getStoreManager();
        R = storeMgr.CastRegion(R, castTy);
        return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
      }
      return LV->getLoc();
    }
    goto DispatchCast;
  }

  // Just pass through function and block pointers.
  if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) {
    assert(Loc::IsLocType(castTy));
    return val;
  }

  // Check for casts from array type to another type.
  if (originalTy->isArrayType()) {
    // We will always decay to a pointer.
    val = StateMgr.ArrayToPointer(cast<Loc>(val));

    // Are we casting from an array to a pointer?  If so just pass on
    // the decayed value.
    if (castTy->isPointerType())
      return val;

    // Are we casting from an array to an integer?  If so, cast the decayed
    // pointer value to an integer.
    assert(castTy->isIntegerType());

    // FIXME: Keep these here for now in case we decide soon that we
    // need the original decayed type.
    //    QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
    //    QualType pointerTy = C.getPointerType(elemTy);
    return evalCastL(cast<Loc>(val), castTy);
  }

  // Check for casts from a region to a specific type.
  if (const MemRegion *R = val.getAsRegion()) {
    // FIXME: We should handle the case where we strip off view layers to get
    //  to a desugared type.

    if (!Loc::IsLocType(castTy)) {
      // FIXME: There can be gross cases where one casts the result of a function
      // (that returns a pointer) to some other value that happens to fit
      // within that pointer value.  We currently have no good way to
      // model such operations.  When this happens, the underlying operation
      // is that the caller is reasoning about bits.  Conceptually we are
      // layering a "view" of a location on top of those bits.  Perhaps
      // we need to be more lazy about mutual possible views, even on an
      // SVal?  This may be necessary for bit-level reasoning as well.
      return UnknownVal();
    }

    // We get a symbolic function pointer for a dereference of a function
    // pointer, but it is of function type. Example:

    //  struct FPRec {
    //    void (*my_func)(int * x);
    //  };
    //
    //  int bar(int x);
    //
    //  int f1_a(struct FPRec* foo) {
    //    int x;
    //    (*foo->my_func)(&x);
    //    return bar(x)+1; // no-warning
    //  }

    assert(Loc::IsLocType(originalTy) || originalTy->isFunctionType() ||
           originalTy->isBlockPointerType());

    StoreManager &storeMgr = StateMgr.getStoreManager();

    // Delegate to store manager to get the result of casting a region to a
    // different type.  If the MemRegion* returned is NULL, this expression
    // Evaluates to UnknownVal.
    R = storeMgr.CastRegion(R, castTy);
    return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
  }

DispatchCast:
  // All other cases.
  return isa<Loc>(val) ? evalCastL(cast<Loc>(val), castTy)
                       : evalCastNL(cast<NonLoc>(val), castTy);
}