Index: include/clang/Basic/Sanitizers.def =================================================================== --- include/clang/Basic/Sanitizers.def +++ include/clang/Basic/Sanitizers.def @@ -65,6 +65,7 @@ SANITIZER("nonnull-attribute", NonnullAttribute) SANITIZER("null", Null) SANITIZER("object-size", ObjectSize) +SANITIZER("pointer-overflow", PointerOverflow) SANITIZER("return", Return) SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute) SANITIZER("shift-base", ShiftBase) @@ -100,9 +101,9 @@ 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) Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -27,6 +27,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" @@ -2791,9 +2792,12 @@ llvm::Value *ptr, ArrayRef indices, bool inbounds, + SourceLocation loc, const llvm::Twine &name = "arrayidx") { if (inbounds) { - return CGF.Builder.CreateInBoundsGEP(ptr, indices, name); + auto *Addr = CGF.Builder.CreateInBoundsGEP(ptr, indices, name); + CGF.EmitInBoundsGEPOverflowCheck(Addr, loc); + return Addr; } else { return CGF.Builder.CreateGEP(ptr, indices, name); } @@ -2826,6 +2830,7 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, ArrayRef indices, QualType eltType, bool inbounds, + SourceLocation loc, const llvm::Twine &name = "arrayidx") { // All the indices except that last must be zero. #ifndef NDEBUG @@ -2846,7 +2851,7 @@ 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); } @@ -2884,7 +2889,8 @@ Address Addr = EmitExtVectorElementLValue(LV); QualType EltType = LV.getType()->castAs()->getElementType(); - Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true); + Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true, + E->getExprLoc()); return MakeAddrLValue(Addr, EltType, LV.getAlignmentSource()); } @@ -2911,7 +2917,8 @@ } Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(), - !getLangOpts().isSignedOverflowDefined()); + !getLangOpts().isSignedOverflowDefined(), + E->getExprLoc()); } else if (const ObjCObjectType *OIT = E->getType()->getAs()){ // Indexing over an interface, as in "NSString *P; P[4];" @@ -2935,7 +2942,8 @@ CharUnits EltAlign = getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize); llvm::Value *EltPtr = - emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false); + emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false, + E->getExprLoc()); Addr = Address(EltPtr, EltAlign); // Cast back. @@ -2959,13 +2967,15 @@ Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx}, E->getType(), - !getLangOpts().isSignedOverflowDefined()); + !getLangOpts().isSignedOverflowDefined(), + E->getExprLoc()); AlignSource = ArrayLV.getAlignmentSource(); } else { // The base must be a pointer; emit it with an estimate of its alignment. Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource); Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(), - !getLangOpts().isSignedOverflowDefined()); + !getLangOpts().isSignedOverflowDefined(), + E->getExprLoc()); } LValue LV = MakeAddrLValue(Addr, E->getType(), AlignSource); @@ -3135,7 +3145,10 @@ else Idx = Builder.CreateNSWMul(Idx, NumElements); EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(), - !getLangOpts().isSignedOverflowDefined()); + !getLangOpts().isSignedOverflowDefined(), + E->getExprLoc()); + if (!getLangOpts().isSignedOverflowDefined()) + EmitInBoundsGEPOverflowCheck(EltPtr.getPointer(), 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 @@ -3154,18 +3167,113 @@ // 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()); AlignSource = ArrayLV.getAlignmentSource(); } else { Address Base = emitOMPArraySectionBase(*this, E->getBase(), AlignSource, BaseTy, ResultExprTy, IsLowerBound); EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy, - !getLangOpts().isSignedOverflowDefined()); + !getLangOpts().isSignedOverflowDefined(), + E->getExprLoc()); } return MakeAddrLValue(EltPtr, ResultExprTy, AlignSource); } +void CodeGenFunction::EmitInBoundsGEPOverflowCheck(llvm::Value *GEPExpr, + SourceLocation Loc) { + // If the pointer overflow sanitizer isn't enabled, do nothing. + if (!SanOpts.has(SanitizerKind::PointerOverflow)) + return; + + // If the GEP has already been reduced to a constant, leave it be. + if (isa(GEPExpr)) + return; + + auto *GEP = cast(GEPExpr); + assert(GEP->isInBounds()); + + SanitizerScope SanScope(this); + const auto &DL = CGM.getDataLayout(); + auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType()); + + // Grab references to the signed add/mult overflow intrinsics for intptr_t: + auto *SAddIntrinsic = + CGM.getIntrinsic(llvm::Intrinsic::sadd_with_overflow, IntPtrTy); + auto *SMulIntrinsic = + CGM.getIntrinsic(llvm::Intrinsic::smul_with_overflow, IntPtrTy); + + // TotalOffset - Sum of offsets for GEP operands visited so far. + llvm::Value *TotalOffset = NULL; + // Valid - True iff final result did not overflow. + llvm::Value *Valid = Builder.getTrue(); + + // Emit check operations for each GEP operand, building up total signed offset + for (auto GTI = llvm::gep_type_begin(GEP), GTE = llvm::gep_type_end(GEP); + GTI != GTE; ++GTI) { + auto *Index = GTI.getOperand(); + llvm::Value *LocalOffset; + // Compute the local offset contributed by this indexing step: + if (auto *STy = dyn_cast(*GTI)) { + // For struct indexing, local offset is position of specified field. + unsigned FieldNo = cast(Index)->getZExtValue(); + LocalOffset = llvm::ConstantInt::get( + IntPtrTy, DL.getStructLayout(STy)->getElementOffset(FieldNo)); + } else { + // Otherwise this is array-like indexing and requires a checked multiply. + auto *ElementSize = llvm::ConstantInt::get( + IntPtrTy, DL.getTypeAllocSize(GTI.getIndexedType())); + auto *IndexS = Builder.CreateIntCast(Index, IntPtrTy, true); + auto *ResultAndOverflow = + Builder.CreateCall(SMulIntrinsic, { ElementSize, IndexS }); + LocalOffset = Builder.CreateExtractValue(ResultAndOverflow, 0); + Valid = Builder.CreateAnd( + Valid, + Builder.CreateNot(Builder.CreateExtractValue(ResultAndOverflow, 1))); + } + + // If this is first offset, use it as total offset. + if (!TotalOffset) { + TotalOffset = LocalOffset; + continue; + } + + // Otherwise add LocalOffset to running total in TotalOffset + auto *TotalAndOverflow = + Builder.CreateCall(SAddIntrinsic, { TotalOffset, LocalOffset }); + TotalOffset = Builder.CreateExtractValue(TotalAndOverflow, 0); + Valid = Builder.CreateAnd( + Valid, + Builder.CreateNot(Builder.CreateExtractValue(TotalAndOverflow, 1))); + } + + // Now that we've computed the (signed) offset as specified + // by all the GEP operands, add it to the unsigned base pointer. + auto *Positive = Builder.CreateICmpSGE( + TotalOffset, llvm::ConstantInt::getNullValue(IntPtrTy)); + auto *PtrInt = Builder.CreatePtrToInt(GEP->getPointerOperand(), IntPtrTy); + + // Compute result, with wrapping semantics + auto *Result = Builder.CreateAdd(PtrInt, TotalOffset); + + // Validity depends on whether the TotalOffset was positive or negative + llvm::Value *PosValid = Builder.CreateICmpUGE(Result, PtrInt); + llvm::Value *NegValid = Builder.CreateICmpULT(Result, PtrInt); + Valid = Builder.CreateAnd(Valid, + Builder.CreateSelect(Positive, PosValid, NegValid)); + + llvm::Constant *StaticArgs[] = { + EmitCheckSourceLocation(Loc) + }; + llvm::Value *DynamicArgs[] = { + EmitCheckValue(GEP->getPointerOperand()), + EmitCheckValue(GEP) + }; + EmitCheck(std::make_pair(Valid, SanitizerKind::PointerOverflow), + "pointer_overflow", StaticArgs, DynamicArgs); +} + LValue CodeGenFunction:: EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { // Emit the base vector as an l-value. Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -347,6 +347,7 @@ llvm::Value *IdxStart[] = { Zero, Zero }; llvm::Value *ArrayStart = Builder.CreateInBoundsGEP(ArrayPtr.getPointer(), IdxStart, "arraystart"); + CGF.EmitInBoundsGEPOverflowCheck(ArrayStart, E->getExprLoc()); CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start); ++Field; @@ -364,6 +365,7 @@ llvm::Value *IdxEnd[] = { Zero, Size }; llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP(ArrayPtr.getPointer(), IdxEnd, "arrayend"); + CGF.EmitInBoundsGEPOverflowCheck(ArrayEnd, E->getExprLoc()); CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength); } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) { // Length. @@ -411,6 +413,7 @@ llvm::Value *indices[] = { zero, zero }; llvm::Value *begin = Builder.CreateInBoundsGEP(DestPtr.getPointer(), indices, "arrayinit.begin"); + CGF.EmitInBoundsGEPOverflowCheck(begin, E->getExprLoc()); CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType); CharUnits elementAlign = @@ -455,6 +458,7 @@ // Advance to the next element. if (i > 0) { element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element"); + CGF.EmitInBoundsGEPOverflowCheck(element, E->getExprLoc()); // Tell the cleanup that it needs to destroy up to this // element. TODO: some of these stores can be trivially @@ -484,6 +488,7 @@ // Advance to the start of the rest of the array. if (NumInitElements) { element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start"); + CGF.EmitInBoundsGEPOverflowCheck(element, E->getExprLoc()); if (endOfInit.isValid()) Builder.CreateStore(element, endOfInit); } @@ -491,6 +496,7 @@ llvm::Value *end = Builder.CreateInBoundsGEP(begin, llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements), "arrayinit.end"); + CGF.EmitInBoundsGEPOverflowCheck(end, E->getExprLoc()); llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body"); @@ -512,6 +518,7 @@ // Move on to the next element. llvm::Value *nextElement = Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next"); + CGF.EmitInBoundsGEPOverflowCheck(nextElement, E->getExprLoc()); // Tell the EH cleanup that we finished with the last element. if (endOfInit.isValid()) Builder.CreateStore(nextElement, endOfInit); Index: lib/CodeGen/CGExprCXX.cpp =================================================================== --- lib/CodeGen/CGExprCXX.cpp +++ lib/CodeGen/CGExprCXX.cpp @@ -1039,6 +1039,7 @@ // Find the end of the array, hoisted out of the loop. llvm::Value *EndPtr = Builder.CreateInBoundsGEP(BeginPtr.getPointer(), NumElements, "array.end"); + EmitInBoundsGEPOverflowCheck(EndPtr, E->getExprLoc()); // If the number of elements isn't constant, we have to now check if there is // anything left to initialize. @@ -1686,6 +1687,7 @@ llvm::Value *arrayBegin = deletedPtr.getPointer(); llvm::Value *arrayEnd = CGF.Builder.CreateInBoundsGEP(arrayBegin, numElements, "delete.end"); + CGF.EmitInBoundsGEPOverflowCheck(arrayEnd, E->getExprLoc()); // Note that it is legal to allocate a zero-length array, and we // can never fold the check away because the length should always @@ -1733,8 +1735,9 @@ GEP.push_back(Zero); } - Ptr = Address(Builder.CreateInBoundsGEP(Ptr.getPointer(), GEP, "del.first"), - Ptr.getAlignment()); + auto Addr = Builder.CreateInBoundsGEP(Ptr.getPointer(), GEP, "del.first"); + Ptr = Address(Addr, Ptr.getAlignment()); + EmitInBoundsGEPOverflowCheck(Addr, E->getExprLoc()); } assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType()); Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -1734,29 +1734,35 @@ = CGF.getContext().getAsVariableArrayType(type)) { llvm::Value *numElts = CGF.getVLASize(vla).first; if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize"); - if (CGF.getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) { value = Builder.CreateGEP(value, numElts, "vla.inc"); - else + } else { value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc"); + CGF.EmitInBoundsGEPOverflowCheck(value, E->getExprLoc()); + } // Arithmetic on function pointers (!) is just +-1. } else if (type->isFunctionType()) { llvm::Value *amt = Builder.getInt32(amount); value = CGF.EmitCastToVoidPtr(value); - if (CGF.getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) { value = Builder.CreateGEP(value, amt, "incdec.funcptr"); - else + } else { value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr"); + CGF.EmitInBoundsGEPOverflowCheck(value, E->getExprLoc()); + } value = Builder.CreateBitCast(value, input->getType()); // For everything else, we can just do a simple increment. } else { llvm::Value *amt = Builder.getInt32(amount); - if (CGF.getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) { value = Builder.CreateGEP(value, amt, "incdec.ptr"); - else + } else { value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr"); + CGF.EmitInBoundsGEPOverflowCheck(value, E->getExprLoc()); + } } // Vector increment/decrement. @@ -1834,10 +1840,12 @@ llvm::Value *sizeValue = llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity()); - if (CGF.getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) { value = Builder.CreateGEP(value, sizeValue, "incdec.objptr"); - else + } else { value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr"); + CGF.EmitInBoundsGEPOverflowCheck(value, E->getExprLoc()); + } value = Builder.CreateBitCast(value, input->getType()); } @@ -2493,6 +2501,7 @@ } else { index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index"); pointer = CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr"); + CGF.EmitInBoundsGEPOverflowCheck(pointer, expr->getExprLoc()); } return pointer; } @@ -2509,7 +2518,9 @@ if (CGF.getLangOpts().isSignedOverflowDefined()) return CGF.Builder.CreateGEP(pointer, index, "add.ptr"); - return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr"); + Value *GEP = CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr"); + CGF.EmitInBoundsGEPOverflowCheck(GEP, expr->getExprLoc()); + return GEP; } // Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1971,6 +1971,9 @@ void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index, QualType IndexType, bool Accessed); + /// \brief Emit overflow checks for inbounds GEP's if enabled. + void EmitInBoundsGEPOverflowCheck(llvm::Value *GEP, SourceLocation Loc); + llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, Index: test/CodeGen/pointer-overflow.c =================================================================== --- test/CodeGen/pointer-overflow.c +++ test/CodeGen/pointer-overflow.c @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=pointer-overflow %s -emit-llvm -o - -O0 | FileCheck %s + +// CHECK-LABEL: @inc( +char *inc(char *p) { + // CHECK: ubsan_handle_pointer_overflow + return p + 1; +} + +// CHECK-LABEL: @dec( +char *dec(char *p) { + // CHECK: ubsan_handle_pointer_overflow + return p - 1; +} + +// CHECK-LABEL: @predec( +char *predec(char *p) { + // CHECK: ubsan_handle_pointer_overflow + return --p; +} + +// CHECK-LABEL: @preinc( +char *preinc(char *p) { + // CHECK: ubsan_handle_pointer_overflow + return ++p; +} + +// CHECK-LABEL: @array( +char *array(char p[10][10], int a, int b) { + // CHECK: ubsan_handle_pointer_overflow + return &p[a][b]; +} + +// CHECK-LABEL: @array_vla( +int array_vla(int n, int a) { + char p[n]; + // CHECK: ubsan_handle_pointer_overflow + char *q = &p[0]; + return n; +} + +// CHECK-LABEL: @array_vla2 +int array_vla2(int n, int a) { + char p[n][n]; + // CHECK: ubsan_handle_pointer_overflow + char (*q)[n] = &p[a]; + + return n; +} + +// CHECK-LABEL: @vla_inc( +int vla_inc(int n) { + char p[n]; + // CHECK: ubsan_handle_pointer_overflow + p[0] = 5; + char (*q)[n] = &p; + // CHECK: ubsan_handle_pointer_overflow + ++q; +} + +typedef void (*FP)(void); + +// CHECK-LABEL: @fp_inc( +FP fp_inc(FP fp, int a) { + // CHECK: ubsan_handle_pointer_overflow + return ++fp; +} + +// CHECK-LABEL: @noop_index( +char *noop_index(char *p) { + // This will be optimized out, + // but would be nice to avoid emitting it. + // CHECK: ubsan_handle_pointer_overflow + return &p[0]; +} Index: test/Driver/fsanitize.c =================================================================== --- test/Driver/fsanitize.c +++ test/Driver/fsanitize.c @@ -3,24 +3,24 @@ // 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|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute|function|pointer-overflow),?){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 // RUN: %clang -target x86_64-pc-win32 -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN64 // RUN: %clang -target x86_64-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-WIN --check-prefix=CHECK-UNDEFINED-WIN64 --check-prefix=CHECK-UNDEFINED-WIN-CXX -// CHECK-UNDEFINED-WIN: "-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: "-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}"}} // CHECK-UNDEFINED-WIN32-SAME: "--dependent-lib={{[^"]*}}ubsan_standalone-i386.lib" // CHECK-UNDEFINED-WIN64-SAME: "--dependent-lib={{[^"]*}}ubsan_standalone-x86_64.lib" // CHECK-UNDEFINED-WIN-CXX-SAME: "--dependent-lib={{[^"]*}}ubsan_standalone_cxx{{[^"]*}}.lib" @@ -38,7 +38,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" @@ -182,7 +182,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|float-cast-overflow|array-bounds|enum|bool|returns-nonnull-attribute|nonnull-attribute|pointer-overflow),?){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