diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -3681,6 +3681,21 @@ if (ReturnBlock.isValid() && ReturnBlock.getBlock()->use_empty()) return; + const AllocAlignAttr *AA = CurCodeDecl->getAttr(); + if (SanOpts.has(SanitizerKind::Alignment) && AA) { + const FunctionDecl *F = dyn_cast(CurCodeDecl); + if (F) { + unsigned PI = AA->getParamIndex().getLLVMIndex(); + llvm::Value *Alignment = CurFn->getArg(PI); + emitAlignmentAssumption(RV, FnRetTy, + // TODO: this first location seems like it should + // be the _return_ statement is, but I'm not quite + // sure how to figure that out from context here? + AA->getLocation(), AA->getLocation(), Alignment, + nullptr); + } + } + ReturnsNonNullAttr *RetNNAttr = nullptr; if (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute)) RetNNAttr = CurCodeDecl->getAttr(); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -671,7 +671,9 @@ bool CodeGenFunction::requiresReturnValueCheck() const { return requiresReturnValueNullabilityCheck() || (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) && CurCodeDecl && - CurCodeDecl->getAttr()); + CurCodeDecl->getAttr()) || + (SanOpts.has(SanitizerKind::Alignment) && CurCodeDecl && + CurCodeDecl->getAttr()); } static bool matchesStlAllocatorFn(const Decl *D, const ASTContext &Ctx) { diff --git a/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function-variable.cpp b/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function-variable.cpp --- a/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function-variable.cpp +++ b/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function-variable.cpp @@ -8,15 +8,37 @@ char **__attribute__((alloc_align(2))) passthrough(char **x, unsigned long alignment) { - // CHECK: define{{.*}} i8** @[[PASSTHROUGH:.*]](i8** noundef %[[X:.*]], i64 noundef %[[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: } + // CHECK: define{{.*}} i8** @[[PASSTHROUGH:.*]](i8** noundef %[[X:.*]], i64 noundef %[[ALIGNMENT:.*]]) + // CHECK-NEXT: entry: + // CHECK-SANITIZE-NEXT: %return.sloc.ptr = alloca i8*, align 8 + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: %[[ALIGNMENT_ADDR:.*]] = alloca i64, align 8 + // CHECK-SANITIZE-NEXT: store i8* null, i8** %return.sloc.ptr, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: store i64 %[[ALIGNMENT]], i64* %[[ALIGNMENT_ADDR]], align 8 + // CHECK-SANITIZE-NEXT: store i8* bitcast ({ [160 x i8]*, i32, i32 }* @0 to i8*), i8** %return.sloc.ptr, align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-SANITIZE-NEXT: %ptrint = ptrtoint i8** %0 to i64 + // CHECK-SANITIZE-NEXT: %[[SUBBED_THING:.*]] = sub i64 %alignment, 1 + // CHECK-SANITIZE-NEXT: %maskedptr = and i64 %ptrint, %[[SUBBED_THING]] + // CHECK-SANITIZE-NEXT: %maskcond = icmp eq i64 %maskedptr, 0 + // CHECK-SANITIZE-NEXT: %[[PTRTOINT:.*]] = ptrtoint i8** %0 to i64, !nosanitize !2 + // CHECK-SANITIZE-NORECOVER-NEXT: br i1 %maskcond, label %cont, label %handler.alignment_assumption, !prof !3, !nosanitize !2 + // CHECK-SANITIZE-TRAP-NEXT: br i1 %maskcond, label %cont, label %trap, !nosanitize !2 + + // CHECK-SANITIZE-ANYRECOVER: handler.alignment_assumption: ; preds = %entry + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ { [160 x i8]*, i32, i32 }, { [160 x i8]*, i32, i32 }, { i16, i16, [10 x i8] }* }* @2 to i8*), i64 %[[PTRTOINT]], i64 %alignment, i64 0) #3, !nosanitize !2 + // CHECK-SANITIZE-NORECOVER-NEXT: unreachable, !nosanitize !2 + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ { [160 x i8]*, i32, i32 }, { [160 x i8]*, i32, i32 }, { i16, i16, [10 x i8] }* }* @2 to i8*), i64 %[[PTRTOINT]], i64 %alignment, i64 0) #3, !nosanitize !2 + // CHECK-SANITIZE-RECOVER-NEXT: br label %cont, !nosanitize !2 + // CHECK-SANITIZE-TRAP: trap: + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.ubsantrap(i8 23) #3, !nosanitize !2 + // CHECK-SANITIZE-TRAP-NEXT: unreachable, !nosanitize !2 + + // CHECK-SANITIZE: cont: + // CHECK-SANITIZE: call void @llvm.assume(i1 true) [ "align"(i8** %0, i64 %alignment) ] + // CHECK-NEXT: ret i8** %[[X_RELOADED]] + // CHECK-NEXT: } return x; } diff --git a/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function.cpp b/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function.cpp --- a/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function.cpp +++ b/clang/test/CodeGen/catch-alignment-assumption-attribute-alloc_align-on-function.cpp @@ -8,15 +8,38 @@ char **__attribute__((alloc_align(2))) passthrough(char **x, unsigned long alignment) { - // CHECK: define{{.*}} i8** @[[PASSTHROUGH:.*]](i8** noundef %[[X:.*]], i64 noundef %[[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: } + // CHECK: define{{.*}} i8** @[[PASSTHROUGH:.*]](i8** noundef %[[X:.*]], i64 noundef %[[ALIGNMENT:.*]]) + // CHECK-NEXT: entry: + // CHECK-SANITIZE-NEXT: %return.sloc.ptr = alloca i8*, align 8 + // CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8 + // CHECK-NEXT: %[[ALIGNMENT_ADDR:.*]] = alloca i64, align 8 + // CHECK-SANITIZE-NEXT: store i8* null, i8** %return.sloc.ptr, align 8 + // CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8 + // CHECK-NEXT: store i64 %[[ALIGNMENT]], i64* %[[ALIGNMENT_ADDR]], align 8 + // CHECK-SANITIZE-NEXT: store i8* bitcast ({ [151 x i8]*, i32, i32 }* @0 to i8*), i8** %return.sloc.ptr, align 8 + // CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8 + // CHECK-SANITIZE-NEXT: %ptrint = ptrtoint i8** %0 to i64 + // CHECK-SANITIZE-NEXT: %1 = sub i64 %alignment, 1 + // CHECK-SANITIZE-NEXT: %maskedptr = and i64 %ptrint, %1 + // CHECK-SANITIZE-NEXT: %maskcond = icmp eq i64 %maskedptr, 0 + // CHECK-SANITIZE-NEXT: %2 = ptrtoint i8** %0 to i64, !nosanitize !2 + // CHECK-SANITIZE-ANYRECOVER-NEXT: br i1 %maskcond, label %cont, label %handler.alignment_assumption, !prof !3, !nosanitize !2 + // CHECK-SANITIZE-TRAP-NEXT: br i1 %maskcond, label %cont, label %trap, !nosanitize !2 + + // CHECK-SANITIZE-ANYRECOVER: handler.alignment_assumption: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ { [151 x i8]*, i32, i32 }, { [151 x i8]*, i32, i32 }, { i16, i16, [10 x i8] }* }* @2 to i8*), i64 %2, i64 %alignment, i64 0) #3, !nosanitize !2 + // CHECK-SANITIZE-NORECOVER-NEXT: unreachable, !nosanitize !2 + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ { [151 x i8]*, i32, i32 }, { [151 x i8]*, i32, i32 }, { i16, i16, [10 x i8] }* }* @2 to i8*), i64 %2, i64 %alignment, i64 0) #3, !nosanitize !2 + // CHECK-SANITIZE-RECOVER-NEXT: br label %cont, !nosanitize !2 + + // CHECK-SANITIZE-TRAP: trap: + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.ubsantrap(i8 23) #3, !nosanitize !2 + // CHECK-SANITIZE-TRAP-NEXT: unreachable, !nosanitize !2 + + // CHECK-SANITIZE: cont: + // CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 true) [ "align"(i8** %[[X_RELOADED]], i64 %[[ALIGNMENT]]) ] + // CHECK-NEXT: ret i8** %[[X_RELOADED]] + // CHECK-NEXT: } return x; }