Taking a look. vedant
> On Jun 1, 2017, at 2:45 PM, Galina Kistanova <gkistan...@gmail.com> wrote: > > 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-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/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/10259> > http://lab.llvm.org:8011/builders/clang-with-lto-ubuntu/builds/3097 > <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@lists.llvm.org <mailto:cfe-commits@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 > <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://wdtz.org/catching-pointer-overflow-bugs.html> > https://reviews.llvm.org/D20322 <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 > <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 > > <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 > > <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 > > <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 > > <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 > > <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 > > <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 > > <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@lists.llvm.org <mailto:cfe-commits@lists.llvm.org> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits