diff options
Diffstat (limited to 'clang/lib/CodeGen/CGExprScalar.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 105 |
1 files changed, 89 insertions, 16 deletions
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 783f74c5026..b9fcb507a6e 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -299,13 +299,31 @@ public: Value *Src, QualType SrcType, QualType DstType, llvm::Type *DstTy, SourceLocation Loc); + /// Known implicit conversion check kinds. + /// Keep in sync with the enum of the same name in ubsan_handlers.h + enum ImplicitConversionCheckKind : unsigned char { + ICCK_IntegerTruncation = 0, + }; + + /// Emit a check that an [implicit] truncation of an integer does not + /// discard any bits. It is not UB, so we use the value after truncation. + void EmitIntegerTruncationCheck(Value *Src, QualType SrcType, Value *Dst, + QualType DstType, SourceLocation Loc); + /// Emit a conversion from the specified type to the specified destination /// type, both of which are LLVM scalar types. - Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy, - SourceLocation Loc); + struct ScalarConversionOpts { + bool TreatBooleanAsSigned; + bool EmitImplicitIntegerTruncationChecks; - Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy, - SourceLocation Loc, bool TreatBooleanAsSigned); + ScalarConversionOpts() + : TreatBooleanAsSigned(false), + EmitImplicitIntegerTruncationChecks(false) {} + }; + Value * + EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy, + SourceLocation Loc, + ScalarConversionOpts Opts = ScalarConversionOpts()); /// Emit a conversion from the specified complex type to the specified /// destination type, where the destination type is an LLVM scalar type. @@ -923,18 +941,59 @@ void ScalarExprEmitter::EmitFloatConversionCheck( SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc); } -/// Emit a conversion from the specified type to the specified destination type, -/// both of which are LLVM scalar types. -Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, - QualType DstType, - SourceLocation Loc) { - return EmitScalarConversion(Src, SrcType, DstType, Loc, false); +void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, + Value *Dst, QualType DstType, + SourceLocation Loc) { + if (!CGF.SanOpts.has(SanitizerKind::ImplicitIntegerTruncation)) + return; + + llvm::Type *SrcTy = Src->getType(); + llvm::Type *DstTy = Dst->getType(); + + // We only care about int->int conversions here. + // We ignore conversions to/from pointer and/or bool. + if (!(SrcType->isIntegerType() && DstType->isIntegerType())) + return; + + assert(isa<llvm::IntegerType>(SrcTy) && isa<llvm::IntegerType>(DstTy) && + "clang integer type lowered to non-integer llvm type"); + + unsigned SrcBits = SrcTy->getScalarSizeInBits(); + unsigned DstBits = DstTy->getScalarSizeInBits(); + // This must be truncation. Else we do not care. + if (SrcBits <= DstBits) + return; + + assert(!DstType->isBooleanType() && "we should not get here with booleans."); + + CodeGenFunction::SanitizerScope SanScope(&CGF); + + llvm::Value *Check = nullptr; + + // 1. Extend the truncated value back to the same width as the Src. + bool InputSigned = DstType->isSignedIntegerOrEnumerationType(); + Check = Builder.CreateIntCast(Dst, SrcTy, InputSigned, "anyext"); + // 2. Equality-compare with the original source value + Check = Builder.CreateICmpEQ(Check, Src, "truncheck"); + // If the comparison result is 'i1 false', then the truncation was lossy. + + llvm::Constant *StaticArgs[] = { + CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType), + CGF.EmitCheckTypeDescriptor(DstType), + llvm::ConstantInt::get(Builder.getInt8Ty(), ICCK_IntegerTruncation)}; + CGF.EmitCheck(std::make_pair(Check, SanitizerKind::ImplicitIntegerTruncation), + SanitizerHandler::ImplicitConversion, StaticArgs, {Src, Dst}); } +/// Emit a conversion from the specified type to the specified destination type, +/// both of which are LLVM scalar types. Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, QualType DstType, SourceLocation Loc, - bool TreatBooleanAsSigned) { + ScalarConversionOpts Opts) { + QualType NoncanonicalSrcType = SrcType; + QualType NoncanonicalDstType = DstType; + SrcType = CGF.getContext().getCanonicalType(SrcType); DstType = CGF.getContext().getCanonicalType(DstType); if (SrcType == DstType) return Src; @@ -1083,7 +1142,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, if (isa<llvm::IntegerType>(SrcTy)) { bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); - if (SrcType->isBooleanType() && TreatBooleanAsSigned) { + if (SrcType->isBooleanType() && Opts.TreatBooleanAsSigned) { InputSigned = true; } if (isa<llvm::IntegerType>(DstTy)) @@ -1118,6 +1177,10 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, } } + if (Opts.EmitImplicitIntegerTruncationChecks) + EmitIntegerTruncationCheck(Src, NoncanonicalSrcType, Res, + NoncanonicalDstType, Loc); + return Res; } @@ -1812,16 +1875,26 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return Builder.CreateVectorSplat(NumElements, Elt, "splat"); } - case CK_IntegralCast: + case CK_IntegralCast: { + ScalarConversionOpts Opts; + if (CGF.SanOpts.has(SanitizerKind::ImplicitIntegerTruncation)) { + if (auto *ICE = dyn_cast<ImplicitCastExpr>(CE)) + Opts.EmitImplicitIntegerTruncationChecks = !ICE->isPartOfExplicitCast(); + } + return EmitScalarConversion(Visit(E), E->getType(), DestTy, + CE->getExprLoc(), Opts); + } case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc()); - case CK_BooleanToSignedIntegral: + case CK_BooleanToSignedIntegral: { + ScalarConversionOpts Opts; + Opts.TreatBooleanAsSigned = true; return EmitScalarConversion(Visit(E), E->getType(), DestTy, - CE->getExprLoc(), - /*TreatBooleanAsSigned=*/true); + CE->getExprLoc(), Opts); + } case CK_IntegralToBoolean: return EmitIntToBoolConversion(Visit(E)); case CK_PointerToBoolean: |