Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -321,6 +321,49 @@ * The Implicit Conversion Sanitizer (``-fsanitize=implicit-conversion``) has learned to sanitize compound assignment operators. +* ``alignment`` check has learned to sanitize the assume_aligned-like attributes: + + .. code-block:: c++ + + typedef char **__attribute__((align_value(1024))) aligned_char; + struct ac_struct { + aligned_char a; + }; + char **load_from_ac_struct(struct ac_struct *x) { + return x->a; // <- check that loaded 'a' is aligned + } + + char **passthrough(__attribute__((align_value(1024))) char **x) { + return x; // <- check the pointer passed as function argument + } + + char **__attribute__((alloc_align(2))) + alloc_align(int size, unsigned long alignment); + + char **caller(int size) { + return alloc_align(size, 1024); // <- check returned pointer + } + + char **__attribute__((assume_aligned(1024))) get_ptr(); + + char **caller2() { + return get_ptr(); // <- check returned pointer + } + + void *caller3(char **x) { + return __builtin_assume_aligned(x, 1024); // <- check returned pointer + } + + void *caller4(char **x, unsigned long offset) { + return __builtin_assume_aligned(x, 1024, offset); // <- check returned pointer accounting for the offest + } + + void process(char *data, int width) { + #pragma omp for simd aligned(data : 1024) // <- aligned clause will be checked. + for (int x = 0; x < width; x++) + data[x] *= data[x]; + } + Core Analysis Improvements ========================== Index: docs/UndefinedBehaviorSanitizer.rst =================================================================== --- docs/UndefinedBehaviorSanitizer.rst +++ docs/UndefinedBehaviorSanitizer.rst @@ -72,7 +72,7 @@ Available checks are: - ``-fsanitize=alignment``: Use of a misaligned pointer or creation - of a misaligned reference. + of a misaligned reference. Also sanitizes assume_aligned-like attributes. - ``-fsanitize=bool``: Load of a ``bool`` value which is neither ``true`` nor ``false``. - ``-fsanitize=builtin``: Passing invalid values to compiler builtins. Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1904,15 +1904,17 @@ return RValue::get(Result); } case Builtin::BI__builtin_assume_aligned: { - Value *PtrValue = EmitScalarExpr(E->getArg(0)); + const Expr *Ptr = E->getArg(0); + Value *PtrValue = EmitScalarExpr(Ptr); Value *OffsetValue = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : nullptr; Value *AlignmentValue = EmitScalarExpr(E->getArg(1)); ConstantInt *AlignmentCI = cast(AlignmentValue); - unsigned Alignment = (unsigned) AlignmentCI->getZExtValue(); + unsigned Alignment = (unsigned)AlignmentCI->getZExtValue(); - EmitAlignmentAssumption(PtrValue, Alignment, OffsetValue); + EmitAlignmentAssumption(PtrValue, Ptr, /*The expr loc is sufficient.*/ SourceLocation(), + Alignment, OffsetValue); return RValue::get(PtrValue); } case Builtin::BI__assume: Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -2410,7 +2410,10 @@ if (!AVAttr) if (const auto *TOTy = dyn_cast(OTy)) AVAttr = TOTy->getDecl()->getAttr(); - if (AVAttr) { + if (AVAttr && !SanOpts.has(SanitizerKind::Alignment)) { + // If alignment-assumption sanitizer is enabled, we do *not* add + // alignment attribute here, but emit normal alignment assumption, + // so the UBSAN check could function. llvm::Value *AlignmentValue = EmitScalarExpr(AVAttr->getAlignment()); llvm::ConstantInt *AlignmentCI = @@ -4535,13 +4538,14 @@ llvm::Value *Alignment = EmitScalarExpr(AA->getAlignment()); llvm::ConstantInt *AlignmentCI = cast(Alignment); - EmitAlignmentAssumption(Ret.getScalarVal(), AlignmentCI->getZExtValue(), - OffsetValue); + EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(), + AlignmentCI->getZExtValue(), OffsetValue); } else if (const auto *AA = TargetDecl->getAttr()) { - llvm::Value *ParamVal = - CallArgs[AA->getParamIndex().getLLVMIndex()].getRValue( - *this).getScalarVal(); - EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal); + llvm::Value *AlignmentVal = CallArgs[AA->getParamIndex().getLLVMIndex()] + .getRValue(*this) + .getScalarVal(); + EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(), + AlignmentVal); } } Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -258,8 +258,11 @@ AVAttr = TTy->getDecl()->getAttr(); } else { // Assumptions for function parameters are emitted at the start of the - // function, so there is no need to repeat that here. - if (isa(VD)) + // function, so there is no need to repeat that here, + // unless the alignment-assumption sanitizer is enabled, + // then we prefer the assumption over alignment attribute + // on IR function param. + if (isa(VD) && !CGF.SanOpts.has(SanitizerKind::Alignment)) return; AVAttr = VD->getAttr(); @@ -276,7 +279,8 @@ Value *AlignmentValue = CGF.EmitScalarExpr(AVAttr->getAlignment()); llvm::ConstantInt *AlignmentCI = cast(AlignmentValue); - CGF.EmitAlignmentAssumption(V, AlignmentCI->getZExtValue()); + CGF.EmitAlignmentAssumption(V, E, AVAttr->getLocation(), + AlignmentCI->getZExtValue()); } /// EmitLoadOfLValue - Given an expression with complex type that represents a Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -1472,7 +1472,8 @@ "alignment is not power of 2"); if (Alignment != 0) { llvm::Value *PtrValue = CGF.EmitScalarExpr(E); - CGF.EmitAlignmentAssumption(PtrValue, Alignment); + CGF.EmitAlignmentAssumption( + PtrValue, E, /*No second loc needed*/ SourceLocation(), Alignment); } } } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -131,6 +131,7 @@ SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \ SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \ SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \ + SANITIZER_CHECK(AlignmentAssumption, alignment_assumption, 0) \ SANITIZER_CHECK(VLABoundNotPositive, vla_bound_not_positive, 0) enum SanitizerHandler { @@ -2633,12 +2634,6 @@ ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); - void EmitAlignmentAssumption(llvm::Value *PtrValue, unsigned Alignment, - llvm::Value *OffsetValue = nullptr) { - Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment, - OffsetValue); - } - /// Converts Location to a DebugLoc, if debug information is enabled. llvm::DebugLoc SourceLocToDebugLoc(SourceLocation Location); @@ -2802,11 +2797,27 @@ PeepholeProtection protectFromPeepholes(RValue rvalue); void unprotectFromPeepholes(PeepholeProtection protection); - void EmitAlignmentAssumption(llvm::Value *PtrValue, llvm::Value *Alignment, - llvm::Value *OffsetValue = nullptr) { - Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment, - OffsetValue); - } + void EmitAlignmentAssumptionCheck(llvm::Value *Ptr, QualType Ty, + SourceLocation Loc, + SourceLocation AssumptionLoc, + llvm::Value *Alignment, + llvm::Value *OffsetValue, + llvm::Value *TheCheck, + llvm::Instruction *Assumption); + + void EmitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty, + SourceLocation Loc, SourceLocation AssumptionLoc, + llvm::Value *Alignment, + llvm::Value *OffsetValue = nullptr); + + void EmitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty, + SourceLocation Loc, SourceLocation AssumptionLoc, + unsigned Alignment, + llvm::Value *OffsetValue = nullptr); + + void EmitAlignmentAssumption(llvm::Value *PtrValue, const Expr *E, + SourceLocation AssumptionLoc, unsigned Alignment, + llvm::Value *OffsetValue = nullptr); //===--------------------------------------------------------------------===// // Statement Emission Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -2207,6 +2207,49 @@ protection.Inst->eraseFromParent(); } +void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue, + QualType Ty, SourceLocation Loc, + SourceLocation AssumptionLoc, + llvm::Value *Alignment, + llvm::Value *OffsetValue) { + llvm::Value *TheCheck; + llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption( + CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck); + if (SanOpts.has(SanitizerKind::Alignment)) { + EmitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, Alignment, + OffsetValue, TheCheck, Assumption); + } +} + +void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue, + QualType Ty, SourceLocation Loc, + SourceLocation AssumptionLoc, + unsigned Alignment, + llvm::Value *OffsetValue) { + llvm::Value *TheCheck; + llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption( + CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck); + if (SanOpts.has(SanitizerKind::Alignment)) { + llvm::Value *AlignmentVal = llvm::ConstantInt::get(IntPtrTy, Alignment); + EmitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, AlignmentVal, + OffsetValue, TheCheck, Assumption); + } +} + +void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue, + const Expr *E, + SourceLocation AssumptionLoc, + unsigned Alignment, + llvm::Value *OffsetValue) { + if (auto *CE = dyn_cast(E)) + E = CE->getSubExprAsWritten(); + QualType Ty = E->getType(); + SourceLocation Loc = E->getExprLoc(); + + EmitAlignmentAssumption(PtrValue, Ty, Loc, AssumptionLoc, Alignment, + OffsetValue); +} + llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Value *AnnotationFn, llvm::Value *AnnotatedVal, StringRef AnnotationStr, @@ -2459,6 +2502,61 @@ Builder.ClearInsertionPoint(); } +// Loc - where the diagnostic will point, where in the source code this +// alignment has failed. +// SecondaryLoc - if present (will be present if sufficiently different from +// Loc), the diagnostic will additionally point a "Note:" to this location. +// It should be the location where the __attribute__((assume_aligned)) +// was written e.g. +void CodeGenFunction::EmitAlignmentAssumptionCheck( + llvm::Value *Ptr, QualType Ty, SourceLocation Loc, + SourceLocation SecondaryLoc, llvm::Value *Alignment, + llvm::Value *OffsetValue, llvm::Value *TheCheck, + llvm::Instruction *Assumption) { + assert(Assumption && isa(Assumption) && + cast(Assumption)->getCalledValue() == + llvm::Intrinsic::getDeclaration( + Builder.GetInsertBlock()->getParent()->getParent(), + llvm::Intrinsic::assume) && + "Assumption should be a call to llvm.assume()."); + assert(&(Builder.GetInsertBlock()->back()) == Assumption && + "Assumption should be the last instruction of the basic block, " + "since the basic block is still being generated."); + + if (!SanOpts.has(SanitizerKind::Alignment)) + return; + + // Don't check pointers to volatile data. The behavior here is implementation- + // defined. + if (Ty->getPointeeType().isVolatileQualified()) + return; + + // We need to temorairly remove the assumption so we can insert the + // sanitizer check before it, else the check will be dropped by optimizations. + Assumption->removeFromParent(); + + { + SanitizerScope SanScope(this); + + if (!OffsetValue) + OffsetValue = Builder.getInt1(0); // no offset. + + llvm::Constant *StaticData[] = {EmitCheckSourceLocation(Loc), + EmitCheckSourceLocation(SecondaryLoc), + EmitCheckTypeDescriptor(Ty)}; + llvm::Value *DynamicData[] = {EmitCheckValue(Ptr), + EmitCheckValue(Alignment), + EmitCheckValue(OffsetValue)}; + EmitCheck({std::make_pair(TheCheck, SanitizerKind::Alignment)}, + SanitizerHandler::AlignmentAssumption, StaticData, DynamicData); + } + + // We are now in the (new, empty) "cont" basic block. + // Reintroduce the assumption. + Builder.Insert(Assumption); + // FIXME: Assumption still has it's original basic block as it's Parent. +} + llvm::DebugLoc CodeGenFunction::SourceLocToDebugLoc(SourceLocation Location) { if (CGDebugInfo *DI = getDebugInfo()) return DI->SourceLocToDebugLoc(Location); Index: test/CodeGen/catch-alignment-assumption-attribute-align_value-on-lvalue.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-attribute-align_value-on-lvalue.cpp +++ test/CodeGen/catch-alignment-assumption-attribute-align_value-on-lvalue.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +typedef char **__attribute__((align_value(0x80000000))) aligned_char; + +struct ac_struct { + // CHECK: %[[STRUCT_AC_STRUCT:.*]] = type { i8** } + aligned_char a; +}; + +// CHECK-SANITIZE-ANYRECOVER: @[[ALIGNED_CHAR:.*]] = {{.*}} c"'aligned_char' (aka 'char **')\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 13 }, {{.*}}* @[[ALIGNED_CHAR]] } + +char **load_from_ac_struct(struct ac_struct *x) { + // CHECK: define i8** @{{.*}}(%[[STRUCT_AC_STRUCT]]* %[[X:.*]]) + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[STRUCT_AC_STRUCT_ADDR:.*]] = alloca %[[STRUCT_AC_STRUCT]]*, align 8 + // CHECK-NEXT: store %[[STRUCT_AC_STRUCT]]* %[[X]], %[[STRUCT_AC_STRUCT]]** %[[STRUCT_AC_STRUCT_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load %[[STRUCT_AC_STRUCT]]*, %[[STRUCT_AC_STRUCT]]** %[[STRUCT_AC_STRUCT_ADDR]], align 8 + // CHECK: %[[A_ADDR:.*]] = getelementptr inbounds %[[STRUCT_AC_STRUCT]], %[[STRUCT_AC_STRUCT]]* %[[X_RELOADED]], i32 0, i32 0 + // CHECK: %[[A:.*]] = load i8**, i8*** %[[A_ADDR]], align 8 + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[A]] to i64 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[A]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8** %[[A]] + // CHECK-NEXT: } +#line 100 + return x->a; +} Index: test/CodeGen/catch-alignment-assumption-attribute-align_value-on-paramvar.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-attribute-align_value-on-paramvar.cpp +++ test/CodeGen/catch-alignment-assumption-attribute-align_value-on-paramvar.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[CHAR]] } + +char **passthrough(__attribute__((align_value(0x80000000))) char **x) { + // CHECK-NOSANITIZE: define i8** @{{.*}}(i8** align 536870912 %[[X:.*]]) + // CHECK-SANITIZE: define i8** @{{.*}}(i8** %[[X:.*]]) + // CHECK-NEXT: [[entry:.*]]: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RELOADED]] to i64 + // CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647 + // CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RELOADED]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8** %[[X_RELOADED]] + // CHECK-NEXT: } +#line 100 + return x; +} Index: test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function-variable.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function-variable.cpp +++ test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function-variable.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[CHAR]] } + +char **__attribute__((alloc_align(2))) +passthrough(char **x, unsigned long alignment) { + // CHECK: define i8** @[[PASSTHROUGH:.*]](i8** %[[X:.*]], i64 %[[ALIGNMENT:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: %[[ALIGNMENT_ADDR:.*]] = alloca i64, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: store i64 %[[ALIGNMENT]], i64* %[[ALIGNMENT_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: ret i8** %[[X_RELOADED]] + // CHECK-NEXT: } + return x; +} + +char **caller(char **x, unsigned long alignment) { + // CHECK: define i8** @{{.*}}(i8** %[[X:.*]], i64 %[[ALIGNMENT:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: %[[ALIGNMENT_ADDR:.*]] = alloca i64, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: store i64 %[[ALIGNMENT]], i64* %[[ALIGNMENT_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[ALIGNMENT_RELOADED:.*]] = load i64, i64* %[[ALIGNMENT_ADDR]], align 8 + // CHECK-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]], i64 %[[ALIGNMENT_RELOADED]]) + // CHECK-NEXT: %[[ISPOSITIVE:.*]] = icmp sgt i64 %[[ALIGNMENT_RELOADED]], 0 + // CHECK-NEXT: %[[POSITIVEMASK:.*]] = sub i64 %[[ALIGNMENT_RELOADED]], 1 + // CHECK-NEXT: %[[MASK:.*]] = select i1 %[[ISPOSITIVE]], i64 %[[POSITIVEMASK]], i64 0 + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], %[[MASK]] + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 %[[ALIGNMENT_RELOADED]], i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 %[[ALIGNMENT_RELOADED]], i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8** %[[X_RETURNED]] + // CHECK-NEXT: } +#line 100 + return passthrough(x, alignment); +} Index: test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function.cpp +++ test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[CHAR]] } + +char **__attribute__((alloc_align(2))) +passthrough(char **x, unsigned long alignment) { + // CHECK: define i8** @[[PASSTHROUGH:.*]](i8** %[[X:.*]], i64 %[[ALIGNMENT:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: %[[ALIGNMENT_ADDR:.*]] = alloca i64, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: store i64 %[[ALIGNMENT]], i64* %[[ALIGNMENT_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: ret i8** %[[X_RELOADED]] + // CHECK-NEXT: } + return x; +} + +char **caller(char **x) { + // CHECK: define i8** @{{.*}}(i8** %[[X:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]], i64 2147483648) + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8** %[[X_RETURNED]] + // CHECK-NEXT: } +#line 100 + return passthrough(x, 0x80000000); +} Index: test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function-two-params.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function-two-params.cpp +++ test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function-two-params.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[CHAR]] } + +char **__attribute__((assume_aligned(0x80000000, 42))) passthrough(char **x) { + // CHECK: define i8** @[[PASSTHROUGH:.*]](i8** %[[X:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: ret i8** %[[X_RELOADED]] + // CHECK-NEXT: } + return x; +} + +char **caller(char **x) { + // CHECK: define i8** @{{.*}}(i8** %[[X:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]]) + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64 + // CHECK-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], 42 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 2147483647 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 42){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 42){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8** %[[X_RETURNED]] + // CHECK-NEXT: } +#line 100 + return passthrough(x); +} Index: test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function.cpp +++ test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[CHAR]] } + +char **__attribute__((assume_aligned(0x80000000))) passthrough(char **x) { + // CHECK: define i8** @[[PASSTHROUGH:.*]](i8** %[[X:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: ret i8** %[[X_RELOADED]] + // CHECK-NEXT: } + return x; +} + +char **caller(char **x) { + // CHECK: define i8** @{{.*}}(i8** %[[X]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]]) + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8** %[[X_RETURNED]] + // CHECK-NEXT: } +#line 100 + return passthrough(x); +} Index: test/CodeGen/catch-alignment-assumption-blacklist.c =================================================================== --- test/CodeGen/catch-alignment-assumption-blacklist.c +++ test/CodeGen/catch-alignment-assumption-blacklist.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK + +// CHECK-LABEL: @baseline +void *baseline(void *x) { + // CHECK: call void @__ubsan_handle_alignment_assumption( + return __builtin_assume_aligned(x, 1); +} + +// CHECK-LABEL: blacklist_0 +__attribute__((no_sanitize("undefined"))) void *blacklist_0(void *x) { + return __builtin_assume_aligned(x, 1); +} + +// CHECK-LABEL: blacklist_1 +__attribute__((no_sanitize("alignment"))) void *blacklist_1(void *x) { + return __builtin_assume_aligned(x, 1); +} + +// CHECK-LABEL: dont_ignore_volatile_ptrs +void *dont_ignore_volatile_ptrs(void * volatile x) { + // CHECK: call void @__ubsan_handle_alignment_assumption( + return __builtin_assume_aligned(x, 1); +} + +// CHECK-LABEL: ignore_volatiles +void *ignore_volatiles(volatile void * x) { + return __builtin_assume_aligned(x, 1); +} Index: test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params-variable.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params-variable.cpp +++ test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params-variable.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}}* @[[CHAR]] } + +void *caller(char **x, unsigned long offset) { + // CHECK: define i8* @{{.*}}(i8** %[[X:.*]], i64 %[[OFFSET:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: %[[OFFSET_ADDR:.*]] = alloca i64, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: store i64 %[[OFFSET]], i64* %[[OFFSET_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[BITCAST:.*]] = bitcast i8** %[[X_RELOADED]] to i8* + // CHECK-NEXT: %[[OFFSET_RELOADED:.*]] = load i64, i64* %[[OFFSET_ADDR]], align 8 + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64 + // CHECK-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], %[[OFFSET_RELOADED]] + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 2147483647 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[BITCAST]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 %[[OFFSET_RELOADED]]){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 %[[OFFSET_RELOADED]]){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8* %[[BITCAST]] + // CHECK-NEXT: } +#line 100 + return __builtin_assume_aligned(x, 0x80000000, offset); +} Index: test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params.cpp +++ test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-three-params.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}}* @[[CHAR]] } + +void *caller(char **x) { + // CHECK: define i8* @{{.*}}(i8** %[[X:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[BITCAST:.*]] = bitcast i8** %[[X_RELOADED]] to i8* + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64 + // CHECK-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], 42 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 2147483647 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[BITCAST]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 42){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 42){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8* %[[BITCAST]] + // CHECK-NEXT: } +#line 100 + return __builtin_assume_aligned(x, 0x80000000, 42); +} Index: test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-two-params.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-two-params.cpp +++ test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-two-params.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}}* @[[CHAR]] } + +void *caller(char **x) { + // CHECK: define i8* @{{.*}}(i8** %[[X:.*]]) + // CHECK-NEXT: entry: + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: %[[BITCAST:.*]] = bitcast i8** %[[X_RELOADED]] to i8* + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[BITCAST]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + // CHECK-NEXT: ret i8* %[[BITCAST]] + // CHECK-NEXT: } +#line 100 + return __builtin_assume_aligned(x, 0x80000000); +} Index: test/CodeGen/catch-alignment-assumption-openmp.cpp =================================================================== --- test/CodeGen/catch-alignment-assumption-openmp.cpp +++ test/CodeGen/catch-alignment-assumption-openmp.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fopenmp-simd -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECK-NOSANITIZE +// RUN: %clang_cc1 -fopenmp-simd -fsanitize=alignment -fno-sanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-NORECOVER,CHECK-SANITIZE-UNREACHABLE +// RUN: %clang_cc1 -fopenmp-simd -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-ANYRECOVER,CHECK-SANITIZE-RECOVER +// RUN: %clang_cc1 -fopenmp-simd -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK,CHECK-SANITIZE,CHECK-SANITIZE-TRAP,CHECK-SANITIZE-UNREACHABLE + +// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char *'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 30 }, {{.*}}* @[[CHAR]] } + +void func(char *data) { + // CHECK: define void @{{.*}}(i8* %[[DATA:.*]]) + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[DATA_ADDR:.*]] = alloca i8*, align 8 + // CHECK: store i8* %[[DATA]], i8** %[[DATA_ADDR]], align 8 + // CHECK: %[[DATA_RELOADED:.*]] = load i8*, i8** %[[DATA_ADDR]], align 8 + // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[DATA_RELOADED]] to i64 + // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 1073741823 + // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[DATA_RELOADED]] to i64, !nosanitize + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 1073741824, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 1073741824, i64 0){{.*}}, !nosanitize + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize + // CHECK-SANITIZE: [[CONT]]: + // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]]) + +#line 100 +#pragma omp for simd aligned(data : 0x40000000) + for (int x = 0; x < 1; x++) + data[x] = data[x]; +}