r304459 - [ubsan] Add a check for pointer overflow UB
Galina Kistanova via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 1 14:45:38 PDT 2017
Hello Vedant,
This commit broke tests on some of our builders:
Failing Tests (1):
Clang :: CodeGen/ubsan-pointer-overflow.m
http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/2865/steps/test-check-all/logs/stdio
http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/10259
http://lab.llvm.org:8011/builders/clang-with-lto-ubuntu/builds/3097
etc
Thanks
Galina
On Thu, Jun 1, 2017 at 12:22 PM, Vedant Kumar via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: vedantk
> Date: Thu Jun 1 14:22:18 2017
> New Revision: 304459
>
> URL: http://llvm.org/viewvc/llvm-project?rev=304459&view=rev
> Log:
> [ubsan] Add a check for pointer overflow UB
>
> Check pointer arithmetic for overflow.
>
> For some more background on this check, see:
>
> https://wdtz.org/catching-pointer-overflow-bugs.html
> https://reviews.llvm.org/D20322
>
> Patch by Will Dietz and John Regehr!
>
> This version of the patch is different from the original in a few ways:
>
> - It introduces the EmitCheckedInBoundsGEP utility which inserts
> checks when the pointer overflow check is enabled.
>
> - It does some constant-folding to reduce instrumentation overhead.
>
> - It does not check some GEPs in CGExprCXX. I'm not sure that
> inserting checks here, or in CGClass, would catch many bugs.
>
> Possible future directions for this check:
>
> - Introduce CGF.EmitCheckedStructGEP, to detect overflows when
> accessing structures.
>
> Testing: Apart from the added lit test, I ran check-llvm and check-clang
> with a stage2, ubsan-instrumented clang. Will and John have also done
> extensive testing on numerous open source projects.
>
> Differential Revision: https://reviews.llvm.org/D33305
>
> Added:
> cfe/trunk/test/CodeGen/ubsan-pointer-overflow.m
> Modified:
> cfe/trunk/docs/UndefinedBehaviorSanitizer.rst
> cfe/trunk/include/clang/Basic/Sanitizers.def
> cfe/trunk/lib/CodeGen/CGExpr.cpp
> cfe/trunk/lib/CodeGen/CGExprScalar.cpp
> cfe/trunk/lib/CodeGen/CodeGenFunction.h
> cfe/trunk/test/Driver/fsanitize.c
>
> Modified: cfe/trunk/docs/UndefinedBehaviorSanitizer.rst
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/
> UndefinedBehaviorSanitizer.rst?rev=304459&r1=304458&r2=304459&view=diff
> ============================================================
> ==================
> --- cfe/trunk/docs/UndefinedBehaviorSanitizer.rst (original)
> +++ cfe/trunk/docs/UndefinedBehaviorSanitizer.rst Thu Jun 1 14:22:18 2017
> @@ -106,6 +106,8 @@ Available checks are:
> invalid pointers. These checks are made in terms of
> ``__builtin_object_size``, and consequently may be able to detect
> more
> problems at higher optimization levels.
> + - ``-fsanitize=pointer-overflow``: Performing pointer arithmetic which
> + overflows.
> - ``-fsanitize=return``: In C++, reaching the end of a
> value-returning function without returning a value.
> - ``-fsanitize=returns-nonnull-attribute``: Returning null pointer
>
> Modified: cfe/trunk/include/clang/Basic/Sanitizers.def
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/Basic/Sanitizers.def?rev=304459&r1=304458&r2=304459&view=diff
> ============================================================
> ==================
> --- cfe/trunk/include/clang/Basic/Sanitizers.def (original)
> +++ cfe/trunk/include/clang/Basic/Sanitizers.def Thu Jun 1 14:22:18 2017
> @@ -73,6 +73,7 @@ SANITIZER("nullability-return", Nullabil
> SANITIZER_GROUP("nullability", Nullability,
> NullabilityArg | NullabilityAssign | NullabilityReturn)
> SANITIZER("object-size", ObjectSize)
> +SANITIZER("pointer-overflow", PointerOverflow)
> SANITIZER("return", Return)
> SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute)
> SANITIZER("shift-base", ShiftBase)
> @@ -108,9 +109,9 @@ SANITIZER("safe-stack", SafeStack)
> SANITIZER_GROUP("undefined", Undefined,
> Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow
> |
> FloatDivideByZero | IntegerDivideByZero |
> NonnullAttribute |
> - Null | ObjectSize | Return | ReturnsNonnullAttribute |
> - Shift | SignedIntegerOverflow | Unreachable |
> VLABound |
> - Function | Vptr)
> + Null | ObjectSize | PointerOverflow | Return |
> + ReturnsNonnullAttribute | Shift |
> SignedIntegerOverflow |
> + Unreachable | VLABound | Function | Vptr)
>
> // -fsanitize=undefined-trap is an alias for -fsanitize=undefined.
> SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined)
>
> Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CGExpr.cpp?rev=304459&r1=304458&r2=304459&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Jun 1 14:22:18 2017
> @@ -3002,9 +3002,10 @@ static llvm::Value *emitArraySubscriptGE
> llvm::Value *ptr,
> ArrayRef<llvm::Value*> indices,
> bool inbounds,
> + SourceLocation loc,
> const llvm::Twine &name = "arrayidx")
> {
> if (inbounds) {
> - return CGF.Builder.CreateInBoundsGEP(ptr, indices, name);
> + return CGF.EmitCheckedInBoundsGEP(ptr, indices, loc, name);
> } else {
> return CGF.Builder.CreateGEP(ptr, indices, name);
> }
> @@ -3035,8 +3036,9 @@ static QualType getFixedSizeElementType(
> }
>
> static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
> - ArrayRef<llvm::Value*> indices,
> + ArrayRef<llvm::Value *> indices,
> QualType eltType, bool inbounds,
> + SourceLocation loc,
> const llvm::Twine &name =
> "arrayidx") {
> // All the indices except that last must be zero.
> #ifndef NDEBUG
> @@ -3057,7 +3059,7 @@ static Address emitArraySubscriptGEP(Cod
> getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
>
> llvm::Value *eltPtr =
> - emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds,
> name);
> + emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds, loc,
> name);
> return Address(eltPtr, eltAlign);
> }
>
> @@ -3110,7 +3112,8 @@ LValue CodeGenFunction::EmitArraySubscri
> Address Addr = EmitExtVectorElementLValue(LV);
>
> QualType EltType = LV.getType()->castAs<
> VectorType>()->getElementType();
> - Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/
> true);
> + Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/
> true,
> + E->getExprLoc());
> return MakeAddrLValue(Addr, EltType, LV.getBaseInfo());
> }
>
> @@ -3138,7 +3141,8 @@ LValue CodeGenFunction::EmitArraySubscri
> }
>
> Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
> - !getLangOpts().
> isSignedOverflowDefined());
> + !getLangOpts().
> isSignedOverflowDefined(),
> + E->getExprLoc());
>
> } else if (const ObjCObjectType *OIT = E->getType()->getAs<
> ObjCObjectType>()){
> // Indexing over an interface, as in "NSString *P; P[4];"
> @@ -3163,8 +3167,8 @@ LValue CodeGenFunction::EmitArraySubscri
> // Do the GEP.
> CharUnits EltAlign =
> getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize);
> - llvm::Value *EltPtr =
> - emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false);
> + llvm::Value *EltPtr = emitArraySubscriptGEP(
> + *this, Addr.getPointer(), ScaledIdx, false, E->getExprLoc());
> Addr = Address(EltPtr, EltAlign);
>
> // Cast back.
> @@ -3189,14 +3193,16 @@ LValue CodeGenFunction::EmitArraySubscri
> Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(),
> {CGM.getSize(CharUnits::Zero()), Idx},
> E->getType(),
> - !getLangOpts().
> isSignedOverflowDefined());
> + !getLangOpts().
> isSignedOverflowDefined(),
> + E->getExprLoc());
> BaseInfo = ArrayLV.getBaseInfo();
> } else {
> // The base must be a pointer; emit it with an estimate of its
> alignment.
> Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo);
> auto *Idx = EmitIdxAfterBase(/*Promote*/true);
> Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
> - !getLangOpts().
> isSignedOverflowDefined());
> + !getLangOpts().
> isSignedOverflowDefined(),
> + E->getExprLoc());
> }
>
> LValue LV = MakeAddrLValue(Addr, E->getType(), BaseInfo);
> @@ -3368,7 +3374,8 @@ LValue CodeGenFunction::EmitOMPArraySect
> else
> Idx = Builder.CreateNSWMul(Idx, NumElements);
> EltPtr = emitArraySubscriptGEP(*this, Base, Idx,
> VLA->getElementType(),
> - !getLangOpts().
> isSignedOverflowDefined());
> + !getLangOpts().
> isSignedOverflowDefined(),
> + E->getExprLoc());
> } else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase()))
> {
> // If this is A[i] where A is an array, the frontend will have
> decayed the
> // base to be a ArrayToPointerDecay implicit cast. While correct, it
> is
> @@ -3387,13 +3394,15 @@ LValue CodeGenFunction::EmitOMPArraySect
> // Propagate the alignment from the array itself to the result.
> EltPtr = emitArraySubscriptGEP(
> *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()),
> Idx},
> - ResultExprTy, !getLangOpts().isSignedOverflowDefined());
> + ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
> + E->getExprLoc());
> BaseInfo = ArrayLV.getBaseInfo();
> } else {
> Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo,
> BaseTy, ResultExprTy,
> IsLowerBound);
> EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
> - !getLangOpts().
> isSignedOverflowDefined());
> + !getLangOpts().
> isSignedOverflowDefined(),
> + E->getExprLoc());
> }
>
> return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo);
>
> Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CGExprScalar.cpp?rev=304459&r1=304458&r2=304459&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Thu Jun 1 14:22:18 2017
> @@ -30,6 +30,7 @@
> #include "llvm/IR/Constants.h"
> #include "llvm/IR/DataLayout.h"
> #include "llvm/IR/Function.h"
> +#include "llvm/IR/GetElementPtrTypeIterator.h"
> #include "llvm/IR/GlobalVariable.h"
> #include "llvm/IR/Intrinsics.h"
> #include "llvm/IR/Module.h"
> @@ -44,6 +45,43 @@ using llvm::Value;
> //===-------------------------------------------------------
> ---------------===//
>
> namespace {
> +
> +/// Determine whether the given binary operation may overflow.
> +/// Sets \p Result to the value of the operation for BO_Add, BO_Sub,
> BO_Mul,
> +/// and signed BO_{Div,Rem}. For these opcodes, and for unsigned
> BO_{Div,Rem},
> +/// the returned overflow check is precise. The returned value is 'true'
> for
> +/// all other opcodes, to be conservative.
> +bool mayHaveIntegerOverflow(llvm::ConstantInt *LHS, llvm::ConstantInt
> *RHS,
> + BinaryOperator::Opcode Opcode, bool Signed,
> + llvm::APInt &Result) {
> + // Assume overflow is possible, unless we can prove otherwise.
> + bool Overflow = true;
> + const auto &LHSAP = LHS->getValue();
> + const auto &RHSAP = RHS->getValue();
> + if (Opcode == BO_Add) {
> + if (Signed)
> + Result = LHSAP.sadd_ov(RHSAP, Overflow);
> + else
> + Result = LHSAP.uadd_ov(RHSAP, Overflow);
> + } else if (Opcode == BO_Sub) {
> + if (Signed)
> + Result = LHSAP.ssub_ov(RHSAP, Overflow);
> + else
> + Result = LHSAP.usub_ov(RHSAP, Overflow);
> + } else if (Opcode == BO_Mul) {
> + if (Signed)
> + Result = LHSAP.smul_ov(RHSAP, Overflow);
> + else
> + Result = LHSAP.umul_ov(RHSAP, Overflow);
> + } else if (Opcode == BO_Div || Opcode == BO_Rem) {
> + if (Signed && !RHS->isZero())
> + Result = LHSAP.sdiv_ov(RHSAP, Overflow);
> + else
> + return false;
> + }
> + return Overflow;
> +}
> +
> struct BinOpInfo {
> Value *LHS;
> Value *RHS;
> @@ -55,37 +93,14 @@ struct BinOpInfo {
> /// Check if the binop can result in integer overflow.
> bool mayHaveIntegerOverflow() const {
> // Without constant input, we can't rule out overflow.
> - const auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS);
> - const auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS);
> + auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS);
> + auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS);
> if (!LHSCI || !RHSCI)
> return true;
>
> - // Assume overflow is possible, unless we can prove otherwise.
> - bool Overflow = true;
> - const auto &LHSAP = LHSCI->getValue();
> - const auto &RHSAP = RHSCI->getValue();
> - if (Opcode == BO_Add) {
> - if (Ty->hasSignedIntegerRepresentation())
> - (void)LHSAP.sadd_ov(RHSAP, Overflow);
> - else
> - (void)LHSAP.uadd_ov(RHSAP, Overflow);
> - } else if (Opcode == BO_Sub) {
> - if (Ty->hasSignedIntegerRepresentation())
> - (void)LHSAP.ssub_ov(RHSAP, Overflow);
> - else
> - (void)LHSAP.usub_ov(RHSAP, Overflow);
> - } else if (Opcode == BO_Mul) {
> - if (Ty->hasSignedIntegerRepresentation())
> - (void)LHSAP.smul_ov(RHSAP, Overflow);
> - else
> - (void)LHSAP.umul_ov(RHSAP, Overflow);
> - } else if (Opcode == BO_Div || Opcode == BO_Rem) {
> - if (Ty->hasSignedIntegerRepresentation() && !RHSCI->isZero())
> - (void)LHSAP.sdiv_ov(RHSAP, Overflow);
> - else
> - return false;
> - }
> - return Overflow;
> + llvm::APInt Result;
> + return ::mayHaveIntegerOverflow(
> + LHSCI, RHSCI, Opcode, Ty->hasSignedIntegerRepresentation(),
> Result);
> }
>
> /// Check if the binop computes a division or a remainder.
> @@ -1925,7 +1940,8 @@ ScalarExprEmitter::EmitScalarPrePostIncD
> if (CGF.getLangOpts().isSignedOverflowDefined())
> value = Builder.CreateGEP(value, numElts, "vla.inc");
> else
> - value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
> + value = CGF.EmitCheckedInBoundsGEP(value, numElts,
> E->getExprLoc(),
> + "vla.inc");
>
> // Arithmetic on function pointers (!) is just +-1.
> } else if (type->isFunctionType()) {
> @@ -1935,7 +1951,8 @@ ScalarExprEmitter::EmitScalarPrePostIncD
> if (CGF.getLangOpts().isSignedOverflowDefined())
> value = Builder.CreateGEP(value, amt, "incdec.funcptr");
> else
> - value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
> + value = CGF.EmitCheckedInBoundsGEP(value, amt, E->getExprLoc(),
> + "incdec.funcptr");
> value = Builder.CreateBitCast(value, input->getType());
>
> // For everything else, we can just do a simple increment.
> @@ -1944,7 +1961,8 @@ ScalarExprEmitter::EmitScalarPrePostIncD
> if (CGF.getLangOpts().isSignedOverflowDefined())
> value = Builder.CreateGEP(value, amt, "incdec.ptr");
> else
> - value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
> + value = CGF.EmitCheckedInBoundsGEP(value, amt, E->getExprLoc(),
> + "incdec.ptr");
> }
>
> // Vector increment/decrement.
> @@ -2025,7 +2043,8 @@ ScalarExprEmitter::EmitScalarPrePostIncD
> if (CGF.getLangOpts().isSignedOverflowDefined())
> value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
> else
> - value = Builder.CreateInBoundsGEP(value, sizeValue,
> "incdec.objptr");
> + value = CGF.EmitCheckedInBoundsGEP(value, sizeValue,
> E->getExprLoc(),
> + "incdec.objptr");
> value = Builder.CreateBitCast(value, input->getType());
> }
>
> @@ -2692,7 +2711,8 @@ static Value *emitPointerArithmetic(Code
> pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");
> } else {
> index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
> - pointer = CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
> + pointer = CGF.EmitCheckedInBoundsGEP(pointer, index,
> op.E->getExprLoc(),
> + "add.ptr");
> }
> return pointer;
> }
> @@ -2709,7 +2729,8 @@ static Value *emitPointerArithmetic(Code
> if (CGF.getLangOpts().isSignedOverflowDefined())
> return CGF.Builder.CreateGEP(pointer, index, "add.ptr");
>
> - return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
> + return CGF.EmitCheckedInBoundsGEP(pointer, index, op.E->getExprLoc(),
> + "add.ptr");
> }
>
> // Construct an fmuladd intrinsic to represent a fused mul-add of MulOp
> and
> @@ -3824,3 +3845,124 @@ LValue CodeGenFunction::EmitCompoundAssi
>
> llvm_unreachable("Unhandled compound assignment operator");
> }
> +
> +Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
> + ArrayRef<Value *> IdxList,
> + SourceLocation Loc,
> + const Twine &Name) {
> + Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
> +
> + // If the pointer overflow sanitizer isn't enabled, do nothing.
> + if (!SanOpts.has(SanitizerKind::PointerOverflow))
> + return GEPVal;
> +
> + // If the GEP has already been reduced to a constant, leave it be.
> + if (isa<llvm::Constant>(GEPVal))
> + return GEPVal;
> +
> + // Only check for overflows in the default address space.
> + if (GEPVal->getType()->getPointerAddressSpace())
> + return GEPVal;
> +
> + auto *GEP = cast<llvm::GEPOperator>(GEPVal);
> + assert(GEP->isInBounds() && "Expected inbounds GEP");
> +
> + SanitizerScope SanScope(this);
> + auto &VMContext = getLLVMContext();
> + const auto &DL = CGM.getDataLayout();
> + auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType());
> +
> + // Grab references to the signed add/mul overflow intrinsics for
> intptr_t.
> + auto *Zero = llvm::ConstantInt::getNullValue(IntPtrTy);
> + auto *SAddIntrinsic =
> + CGM.getIntrinsic(llvm::Intrinsic::sadd_with_overflow, IntPtrTy);
> + auto *SMulIntrinsic =
> + CGM.getIntrinsic(llvm::Intrinsic::smul_with_overflow, IntPtrTy);
> +
> + // The total (signed) byte offset for the GEP.
> + llvm::Value *TotalOffset = nullptr;
> + // The offset overflow flag - true if the total offset overflows.
> + llvm::Value *OffsetOverflows = Builder.getFalse();
> +
> + /// Return the result of the given binary operation.
> + auto eval = [&](BinaryOperator::Opcode Opcode, llvm::Value *LHS,
> + llvm::Value *RHS) -> llvm::Value * {
> + assert(Opcode == BO_Add || Opcode == BO_Mul && "Can't eval binop");
> +
> + // If the operands are constants, return a constant result.
> + if (auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS)) {
> + if (auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS)) {
> + llvm::APInt N;
> + bool HasOverflow = mayHaveIntegerOverflow(LHSCI, RHSCI, Opcode,
> + /*Signed=*/true, N);
> + if (HasOverflow)
> + OffsetOverflows = Builder.getTrue();
> + return llvm::ConstantInt::get(VMContext, N);
> + }
> + }
> +
> + // Otherwise, compute the result with checked arithmetic.
> + auto *ResultAndOverflow = Builder.CreateCall(
> + (Opcode == BO_Add) ? SAddIntrinsic : SMulIntrinsic, {LHS, RHS});
> + OffsetOverflows = Builder.CreateOr(
> + OffsetOverflows, Builder.CreateExtractValue(ResultAndOverflow,
> 1));
> + return Builder.CreateExtractValue(ResultAndOverflow, 0);
> + };
> +
> + // Determine the total byte offset by looking at each GEP operand.
> + for (auto GTI = llvm::gep_type_begin(GEP), GTE =
> llvm::gep_type_end(GEP);
> + GTI != GTE; ++GTI) {
> + llvm::Value *LocalOffset;
> + auto *Index = GTI.getOperand();
> + // Compute the local offset contributed by this indexing step:
> + if (auto *STy = GTI.getStructTypeOrNull()) {
> + // For struct indexing, the local offset is the byte position of the
> + // specified field.
> + unsigned FieldNo = cast<llvm::ConstantInt>(Index)->getZExtValue();
> + LocalOffset = llvm::ConstantInt::get(
> + IntPtrTy, DL.getStructLayout(STy)->getElementOffset(FieldNo));
> + } else {
> + // Otherwise this is array-like indexing. The local offset is the
> index
> + // multiplied by the element size.
> + auto *ElementSize = llvm::ConstantInt::get(
> + IntPtrTy, DL.getTypeAllocSize(GTI.getIndexedType()));
> + auto *IndexS = Builder.CreateIntCast(Index, IntPtrTy,
> /*isSigned=*/true);
> + LocalOffset = eval(BO_Mul, ElementSize, IndexS);
> + }
> +
> + // If this is the first offset, set it as the total offset.
> Otherwise, add
> + // the local offset into the running total.
> + if (!TotalOffset || TotalOffset == Zero)
> + TotalOffset = LocalOffset;
> + else
> + TotalOffset = eval(BO_Add, TotalOffset, LocalOffset);
> + }
> +
> + // Common case: if the total offset is zero, don't emit a check.
> + if (TotalOffset == Zero)
> + return GEPVal;
> +
> + // Now that we've computed the total offset, add it to the base pointer
> (with
> + // wrapping semantics).
> + auto *IntPtr = Builder.CreatePtrToInt(GEP->getPointerOperand(),
> IntPtrTy);
> + auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset);
> +
> + // The GEP is valid if:
> + // 1) The total offset doesn't overflow, and
> + // 2) The sign of the difference between the computed address and the
> base
> + // pointer matches the sign of the total offset.
> + llvm::Value *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP,
> IntPtr);
> + llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
> + auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
> + llvm::Value *ValidGEP = Builder.CreateAnd(
> + Builder.CreateNot(OffsetOverflows),
> + Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid));
> +
> + llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)};
> + // Pass the computed GEP to the runtime to avoid emitting poisoned
> arguments.
> + llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
> + EmitCheck(std::make_pair(ValidGEP, SanitizerKind::PointerOverflow),
> + SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
> +
> + return GEPVal;
> +}
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CodeGenFunction.h?rev=304459&r1=304458&r2=304459&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Jun 1 14:22:18 2017
> @@ -120,6 +120,7 @@ enum TypeEvaluationKind {
> SANITIZER_CHECK(NonnullArg, nonnull_arg, 0)
> \
> SANITIZER_CHECK(NonnullReturn, nonnull_return, 0)
> \
> SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0)
> \
> + SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0)
> \
> SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0)
> \
> SANITIZER_CHECK(SubOverflow, sub_overflow, 0)
> \
> SANITIZER_CHECK(TypeMismatch, type_mismatch, 1)
> \
> @@ -3551,6 +3552,13 @@ public:
> /// nonnull, if \p LHS is marked _Nonnull.
> void EmitNullabilityCheck(LValue LHS, llvm::Value *RHS, SourceLocation
> Loc);
>
> + /// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a
> check to
> + /// detect undefined behavior when the pointer overflow sanitizer is
> enabled.
> + llvm::Value *EmitCheckedInBoundsGEP(llvm::Value *Ptr,
> + ArrayRef<llvm::Value *> IdxList,
> + SourceLocation Loc,
> + const Twine &Name = "");
> +
> /// \brief Emit a description of a type in a format suitable for
> passing to
> /// a runtime sanitizer handler.
> llvm::Constant *EmitCheckTypeDescriptor(QualType T);
>
> Added: cfe/trunk/test/CodeGen/ubsan-pointer-overflow.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
> CodeGen/ubsan-pointer-overflow.m?rev=304459&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/CodeGen/ubsan-pointer-overflow.m (added)
> +++ cfe/trunk/test/CodeGen/ubsan-pointer-overflow.m Thu Jun 1 14:22:18
> 2017
> @@ -0,0 +1,171 @@
> +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -w -emit-llvm -o - %s
> -fsanitize=pointer-overflow | FileCheck %s
> +
> +// CHECK-LABEL: define void @unary_arith
> +void unary_arith(char *p) {
> + // CHECK: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
> + // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 1, !nosanitize
> + // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]],
> !nosanitize
> + // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]],
> !nosanitize
> + // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 true, i1 [[POSVALID]], i1
> [[NEGVALID]], !nosanitize
> + // CHECK-NEXT: [[VALID:%.*]] = and i1 true, [[DIFFVALID]], !nosanitize
> + // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64
> [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
> + ++p;
> +
> + // CHECK: ptrtoint i8* {{.*}} to i64, !nosanitize
> + // CHECK-NEXT: add i64 {{.*}}, -1, !nosanitize
> + // CHECK: select i1 false{{.*}}, !nosanitize
> + // CHECK-NEXT: and i1 true{{.*}}, !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> + --p;
> +
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> + p++;
> +
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> + p--;
> +}
> +
> +// CHECK-LABEL: define void @binary_arith
> +void binary_arith(char *p, int i) {
> + // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64
> 1, i64 %{{.*}}), !nosanitize
> + // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]],
> 1, !nosanitize
> + // CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]],
> !nosanitize
> + // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0,
> !nosanitize
> + // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize
> + // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]],
> !nosanitize
> + // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]],
> !nosanitize
> + // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]],
> !nosanitize
> + // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0,
> !nosanitize
> + // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true,
> !nosanitize
> + // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1
> [[POSVALID]], i1 [[NEGVALID]], !nosanitize
> + // CHECK-NEXT: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]],
> !nosanitize
> + // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64
> [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
> + p + i;
> +
> + // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}}
> + // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]]
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> + p - i;
> +}
> +
> +// CHECK-LABEL: define void @fixed_len_array
> +void fixed_len_array(int k) {
> + // CHECK: getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]*
> [[ARR:%.*]], i64 0, i64 [[IDXPROM:%.*]]
> + // CHECK-NEXT: [[SMUL:%.*]] = call { i64, i1 }
> @llvm.smul.with.overflow.i64(i64 40, i64 [[IDXPROM]]), !nosanitize
> + // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]],
> 1, !nosanitize
> + // CHECK-NEXT: [[OFFSETOFLOW:%.*]] = or i1 false, [[SMULOFLOW]],
> !nosanitize
> + // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0,
> !nosanitize
> + // CHECK-NEXT: [[BASE:%.*]] = ptrtoint [10 x [10 x i32]]* [[ARR]] to
> i64, !nosanitize
> + // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]],
> !nosanitize
> + // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]],
> !nosanitize
> + // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]],
> !nosanitize
> + // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0,
> !nosanitize
> + // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[OFFSETOFLOW]], true,
> !nosanitize
> + // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1
> [[POSVALID]], i1 [[NEGVALID]], !nosanitize
> + // CHECK-NEXT: [[VALID:%.*]] = and i1 [[OFFSETVALID]], [[DIFFVALID]],
> !nosanitize
> + // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64
> [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize
> +
> + // CHECK: getelementptr inbounds [10 x i32], [10 x i32]* {{.*}}, i64 0,
> i64 [[IDXPROM1:%.*]]
> + // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM1]]),
> !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> +
> + int arr[10][10];
> + arr[k][k];
> +}
> +
> +// CHECK-LABEL: define void @variable_len_array
> +void variable_len_array(int n, int k) {
> + // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]]
> + // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]),
> !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> +
> + // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM1:%.*]]
> + // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM1]]),
> !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> +
> + int arr[n][n];
> + arr[k][k];
> +}
> +
> +// CHECK-LABEL: define void @pointer_array
> +void pointer_array(int **arr, int k) {
> + // CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> +
> + // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 {{.*}}), !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> +
> + arr[k][k];
> +}
> +
> +struct S1 {
> + int pad1;
> + union {
> + char leaf;
> + struct S1 *link;
> + } u;
> + struct S1 *arr;
> +};
> +
> +// TODO: Currently, structure GEPs are not checked, so there are several
> +// potentially unsafe GEPs here which we don't instrument.
> +//
> +// CHECK-LABEL: define void @struct_index
> +void struct_index(struct S1 *p) {
> + // CHECK: getelementptr inbounds %struct.S1, %struct.S1* [[P:%.*]], i64
> 10
> + // CHECK-NEXT: [[BASE:%.*]] = ptrtoint %struct.S1* [[P]] to i64,
> !nosanitize
> + // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 240, !nosanitize
> + // CHECK: @__ubsan_handle_pointer_overflow{{.*}} i64 [[BASE]], i64
> [[COMPGEP]]) {{.*}}, !nosanitize
> +
> + // CHECK-NOT: @__ubsan_handle_pointer_overflow
> +
> + p->arr[10].u.link->u.leaf;
> +}
> +
> +typedef void (*funcptr_t)(void);
> +
> +// CHECK-LABEL: define void @function_pointer_arith
> +void function_pointer_arith(funcptr_t *p, int k) {
> + // CHECK: add i64 {{.*}}, 8, !nosanitize
> + // CHECK: @__ubsan_handle_pointer_overflow{{.*}}
> + ++p;
> +
> + // CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> + p + k;
> +}
> +
> +// CHECK-LABEL: define void @variable_len_array_arith
> +void variable_len_array_arith(int n, int k) {
> + int vla[n];
> + int (*p)[n] = &vla;
> +
> + // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[INC:%.*]]
> + // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[INC]]), !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> + ++p;
> +
> + // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]]
> + // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]),
> !nosanitize
> + // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}
> + p + k;
> +}
> +
> +// CHECK-LABEL: define void @objc_id
> +void objc_id(id *p) {
> + // CHECK: add i64 {{.*}}, 8, !nosanitize
> + // CHECK: @__ubsan_handle_pointer_overflow{{.*}}
> + p++;
> +}
> +
> +// CHECK-LABEL: define void @dont_emit_checks_for_no_op_GEPs
> +// CHECK-NOT: __ubsan_handle_pointer_overflow
> +void dont_emit_checks_for_no_op_GEPs(char *p) {
> + &p[0];
> +
> + int arr[10][10];
> + &arr[0][0];
> +}
>
> Modified: cfe/trunk/test/Driver/fsanitize.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/
> fsanitize.c?rev=304459&r1=304458&r2=304459&view=diff
> ============================================================
> ==================
> --- cfe/trunk/test/Driver/fsanitize.c (original)
> +++ cfe/trunk/test/Driver/fsanitize.c Thu Jun 1 14:22:18 2017
> @@ -3,18 +3,18 @@
> // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined
> -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s
> --check-prefix=CHECK-UNDEFINED-TRAP
> // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap
> -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s
> --check-prefix=CHECK-UNDEFINED-TRAP
> // RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-error
> -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-
> UNDEFINED-TRAP
> -// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-
> divide-by-zero|float-divide-by-zero|shift-base|shift-
> exponent|unreachable|return|vla-bound|alignment|null|
> object-size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-
> attribute|nonnull-attribute|function),?){18}"}}
> -// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,
> array-bounds,bool,enum,float-cast-overflow,float-divide-by-
> zero,function,integer-divide-by-zero,nonnull-attribute,
> null,object-size,return,returns-nonnull-attribute,
> shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
> -// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,
> array-bounds,bool,enum,float-cast-overflow,float-divide-by-
> zero,function,integer-divide-by-zero,nonnull-attribute,
> null,object-size,return,returns-nonnull-attribute,
> shift-base,shift-exponent,unreachable,vla-bound"
> +// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-
> divide-by-zero|float-divide-by-zero|shift-base|shift-
> exponent|unreachable|return|vla-bound|alignment|null|
> object-size|pointer-overflow|float-cast-overflow|array-
> bounds|enum|bool|returns-nonnull-attribute|nonnull-
> attribute|function),?){19}"}}
> +// CHECK-UNDEFINED-TRAP: "-fsanitize-trap=alignment,
> array-bounds,bool,enum,float-cast-overflow,float-divide-by-
> zero,function,integer-divide-by-zero,nonnull-attribute,
> null,object-size,pointer-overflow,return,returns-
> nonnull-attribute,shift-base,shift-exponent,signed-integer-
> overflow,unreachable,vla-bound"
> +// CHECK-UNDEFINED-TRAP2: "-fsanitize-trap=alignment,
> array-bounds,bool,enum,float-cast-overflow,float-divide-by-
> zero,function,integer-divide-by-zero,nonnull-attribute,
> null,object-size,pointer-overflow,return,returns-
> nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
>
> // RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1
> | FileCheck %s --check-prefix=CHECK-UNDEFINED
> -// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-
> divide-by-zero|float-divide-by-zero|function|shift-base|
> shift-exponent|unreachable|return|vla-bound|alignment|
> null|vptr|object-size|float-cast-overflow|array-bounds|
> enum|bool|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
> +// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-
> divide-by-zero|float-divide-by-zero|function|shift-base|
> shift-exponent|unreachable|return|vla-bound|alignment|
> null|vptr|object-size|pointer-overflow|float-cast-overflow|
> array-bounds|enum|bool|returns-nonnull-attribute|
> nonnull-attribute),?){20}"}}
>
> // RUN: %clang -target x86_64-apple-darwin10 -fsanitize=undefined %s -###
> 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN
> -// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|shift-base|shift-exponent|unreachable|return|
> vla-bound|alignment|null|object-size|float-cast-
> overflow|array-bounds|enum|bool|returns-nonnull-
> attribute|nonnull-attribute),?){17}"}}
> +// CHECK-UNDEFINED-DARWIN: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|shift-base|shift-exponent|unreachable|return|
> vla-bound|alignment|null|object-size|pointer-overflow|
> float-cast-overflow|array-bounds|enum|bool|returns-
> nonnull-attribute|nonnull-attribute),?){18}"}}
>
> // RUN: %clang -target i386-unknown-openbsd -fsanitize=undefined %s -###
> 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-OPENBSD
> -// CHECK-UNDEFINED-OPENBSD: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|shift-base|shift-exponent|unreachable|return|
> vla-bound|alignment|null|object-size|float-cast-
> overflow|array-bounds|enum|bool|returns-nonnull-
> attribute|nonnull-attribute),?){17}"}}
> +// CHECK-UNDEFINED-OPENBSD: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|shift-base|shift-exponent|unreachable|return|
> vla-bound|alignment|null|object-size|pointer-overflow|
> float-cast-overflow|array-bounds|enum|bool|returns-
> nonnull-attribute|nonnull-attribute),?){18}"}}
>
> // RUN: %clang -target i386-pc-win32 -fsanitize=undefined %s -### 2>&1 |
> FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-
> UNDEFINED-WIN32
> // RUN: %clang -target i386-pc-win32 -fsanitize=undefined -x c++ %s -###
> 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN
> --check-prefix=CHECK-UNDEFINED-WIN32 --check-prefix=CHECK-
> UNDEFINED-WIN-CXX
> @@ -23,7 +23,7 @@
> // CHECK-UNDEFINED-WIN32: "--dependent-lib={{[^"]*}}
> ubsan_standalone-i386.lib"
> // CHECK-UNDEFINED-WIN64: "--dependent-lib={{[^"]*}}
> ubsan_standalone-x86_64.lib"
> // CHECK-UNDEFINED-WIN-CXX: "--dependent-lib={{[^"]*}}
> ubsan_standalone_cxx{{[^"]*}}.lib"
> -// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|shift-base|shift-exponent|unreachable|return|
> vla-bound|alignment|null|object-size|float-cast-
> overflow|array-bounds|enum|bool|returns-nonnull-
> attribute|nonnull-attribute),?){17}"}}
> +// CHECK-UNDEFINED-WIN-SAME: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|shift-base|shift-exponent|unreachable|return|
> vla-bound|alignment|null|object-size|pointer-overflow|
> float-cast-overflow|array-bounds|enum|bool|returns-
> nonnull-attribute|nonnull-attribute),?){18}"}}
>
> // RUN: %clang -target i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1
> | FileCheck %s --check-prefix=CHECK-COVERAGE-WIN32
> // CHECK-COVERAGE-WIN32: "--dependent-lib={{[^"]*}}
> ubsan_standalone-i386.lib"
> @@ -43,7 +43,7 @@
> // CHECK-FNO-SANITIZE-ALL: "-fsanitize=thread"
>
> // RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined
> -fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,enum %s
> -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
> -// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|function|shift-base|shift-exponent|unreachable|
> return|vla-bound|alignment|null|object-size|array-bounds|
> returns-nonnull-attribute|nonnull-attribute),?){15}"}}
> +// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-
> integer-overflow|integer-divide-by-zero|float-divide-
> by-zero|function|shift-base|shift-exponent|unreachable|
> return|vla-bound|alignment|null|object-size|pointer-
> overflow|array-bounds|returns-nonnull-attribute|nonnull-
> attribute),?){16}"}}
>
> // RUN: %clang -target x86_64-linux-gnu -fsanitize=shift
> -fno-sanitize=shift-base %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-
> FSANITIZE-SHIFT-PARTIAL
> // CHECK-FSANITIZE-SHIFT-PARTIAL: "-fsanitize=shift-exponent"
> @@ -217,7 +217,7 @@
> // RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined
> -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s
> --check-prefix=CHECK-NO-RECOVER-UBSAN
> // RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined
> -fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck
> %s --check-prefix=CHECK-NO-RECOVER-UBSAN
> // RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined
> -fsanitize-recover=all -fno-sanitize-recover=undefined -### 2>&1 |
> FileCheck %s --check-prefix=CHECK-NO-RECOVER-UBSAN
> -// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|
> integer-divide-by-zero|float-divide-by-zero|function|shift-
> base|shift-exponent|vla-bound|alignment|null|vptr|object-
> size|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|
> nonnull-attribute),?){17}"}}
> +// CHECK-RECOVER-UBSAN: "-fsanitize-recover={{((signed-integer-overflow|
> integer-divide-by-zero|float-divide-by-zero|function|shift-
> base|shift-exponent|vla-bound|alignment|null|vptr|object-
> size|pointer-overflow|float-cast-overflow|array-bounds|
> enum|bool|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
> // CHECK-NO-RECOVER-UBSAN-NOT: sanitize-recover
>
> // RUN: %clang -target x86_64-linux-gnu %s -fsanitize=undefined
> -fno-sanitize-recover=all -fsanitize-recover=object-size,shift-base -###
> 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170601/2f27b75f/attachment-0001.html>
More information about the cfe-commits
mailing list