/// 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); }
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(); }
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; }
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; }
// 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); }