diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3188,7 +3188,7 @@ PeepholeProtection protectFromPeepholes(RValue rvalue); void unprotectFromPeepholes(PeepholeProtection protection); - void emitAlignmentAssumptionCheck(llvm::Value *Ptr, QualType Ty, + void emitAlignmentAssumptionCheck(llvm::Value *Ptr, QualType WrittenTy, SourceLocation Loc, SourceLocation AssumptionLoc, llvm::Value *Alignment, @@ -3196,12 +3196,12 @@ llvm::Value *TheCheck, llvm::Instruction *Assumption); - void emitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty, + void emitAlignmentAssumption(llvm::Value *PtrValue, QualType PtrTy, SourceLocation Loc, SourceLocation AssumptionLoc, llvm::Value *Alignment, llvm::Value *OffsetValue = nullptr); - void emitAlignmentAssumption(llvm::Value *PtrValue, const Expr *E, + void emitAlignmentAssumption(llvm::Value *PtrValue, const Expr *PtrExpr, SourceLocation AssumptionLoc, llvm::Value *Alignment, llvm::Value *OffsetValue = nullptr); 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 @@ -2409,7 +2409,8 @@ } void CodeGenFunction::emitAlignmentAssumption(llvm::Value *PtrValue, - QualType Ty, SourceLocation Loc, + QualType WrittenTy, + SourceLocation Loc, SourceLocation AssumptionLoc, llvm::Value *Alignment, llvm::Value *OffsetValue) { @@ -2444,19 +2445,24 @@ if (!SanOpts.has(SanitizerKind::Alignment)) return; - emitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, Alignment, - OffsetValue, TheCheck, Assumption); + emitAlignmentAssumptionCheck(PtrValue, WrittenTy, Loc, AssumptionLoc, + Alignment, OffsetValue, TheCheck, Assumption); } void CodeGenFunction::emitAlignmentAssumption(llvm::Value *PtrValue, - const Expr *E, + const Expr *PtrExpr, SourceLocation AssumptionLoc, llvm::Value *Alignment, llvm::Value *OffsetValue) { - QualType Ty = E->getType(); - SourceLocation Loc = E->getExprLoc(); - - emitAlignmentAssumption(PtrValue, Ty, Loc, AssumptionLoc, Alignment, + // Written type used to build TypeDescriptor. + QualType WrittenTy; + if (auto *CE = dyn_cast(PtrExpr)) { + WrittenTy = CE->getSubExprAsWritten()->getType(); + } else { + WrittenTy = PtrExpr->getType(); + } + SourceLocation Loc = PtrExpr->getExprLoc(); + emitAlignmentAssumption(PtrValue, WrittenTy, Loc, AssumptionLoc, Alignment, OffsetValue); } @@ -2806,7 +2812,7 @@ // It should be the location where the __attribute__((assume_aligned)) // was written e.g. void CodeGenFunction::emitAlignmentAssumptionCheck( - llvm::Value *Ptr, QualType Ty, SourceLocation Loc, + llvm::Value *Ptr, QualType WrittenTy, SourceLocation Loc, SourceLocation SecondaryLoc, llvm::Value *Alignment, llvm::Value *OffsetValue, llvm::Value *TheCheck, llvm::Instruction *Assumption) { @@ -2825,8 +2831,13 @@ // Don't check pointers to volatile data. The behavior here is implementation- // defined. - if (Ty->getPointeeType().isVolatileQualified()) + // The volatile qualifier on PtrTy will be ignored in Sema, we try to find + // volatile in WrittenTy as a workaround. + if ((WrittenTy->isPointerType() && + WrittenTy->getPointeeType().isVolatileQualified()) || + (WrittenTy->isArrayType() && WrittenTy.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. @@ -2840,7 +2851,7 @@ llvm::Constant *StaticData[] = {EmitCheckSourceLocation(Loc), EmitCheckSourceLocation(SecondaryLoc), - EmitCheckTypeDescriptor(Ty)}; + EmitCheckTypeDescriptor(WrittenTy)}; llvm::Value *DynamicData[] = {EmitCheckValue(Ptr), EmitCheckValue(Alignment), EmitCheckValue(OffsetValue)}; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8012,17 +8012,8 @@ if (checkArgCountRange(*this, TheCall, 2, 3)) return true; - unsigned NumArgs = TheCall->getNumArgs(); - Expr *FirstArg = TheCall->getArg(0); - - { - ExprResult FirstArgResult = - DefaultFunctionArrayLvalueConversion(FirstArg); - if (checkBuiltinArgument(*this, TheCall, 0)) - return true; - /// In-place updation of FirstArg by checkBuiltinArgument is ignored. - TheCall->setArg(0, FirstArgResult.get()); - } + if (checkBuiltinArgument(*this, TheCall, 0)) + return true; // The alignment must be a constant integer. Expr *SecondArg = TheCall->getArg(1); @@ -8042,7 +8033,7 @@ << SecondArg->getSourceRange() << Sema::MaximumAlignment; } - if (NumArgs > 2) { + if (TheCall->getNumArgs() > 2) { Expr *ThirdArg = TheCall->getArg(2); if (convertArgumentToType(*this, ThirdArg, Context.getSizeType())) return true; diff --git a/clang/test/CodeGen/catch-alignment-assumption-array.c b/clang/test/CodeGen/catch-alignment-assumption-array.c --- a/clang/test/CodeGen/catch-alignment-assumption-array.c +++ b/clang/test/CodeGen/catch-alignment-assumption-array.c @@ -3,7 +3,7 @@ // 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: @[[CHAR:.*]] = {{.*}} c"'char[1]'\00" } // CHECK-SANITIZE-ANYRECOVER: @[[ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 30, i32 35 }, {{.*}} @[[CHAR]] } void *caller(void) { diff --git a/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-polymorphism-no-opaque-ptr.cpp b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-polymorphism-no-opaque-ptr.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/catch-alignment-assumption-builtin_assume_aligned-polymorphism-no-opaque-ptr.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s +// RUN: %clang_cc1 -no-opaque-pointers -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 -no-opaque-pointers -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 -no-opaque-pointers -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"'B *'\00" } +// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 35 }, {{.*}} @[[CHAR]] } + +struct A { int n; }; +struct B { int n; }; +struct C : A, B {}; + +void *f(C *c) { + // CHECK: define {{.*}} i8* @{{.*}}(%struct.C* noundef %[[C:.*]]) {{.*}} { + // CHECK-NEXT: [[ENTRY:.*]]: + // CHECK-NEXT: %[[C_ADDR:.*]] = alloca %struct.C* + // CHECK-NEXT: store %struct.C* %[[C]], %struct.C** %[[C_ADDR]] + // CHECK-NEXT: %[[C_RELOAD:.*]] = load %struct.C*, %struct.C** %[[C_ADDR]] + // CHECK-NEXT: %[[IS_NULL:.*]] = icmp eq %struct.C* %[[C_RELOAD]], null + // CHECK-NEXT: br i1 %[[IS_NULL]], label %[[CAST_END:[^,]+]], label %[[CAST_NOT_NULL:[^,]+]] + // CHECK: [[CAST_NOT_NULL]]: + // CHECK-NOSANITIZE-NEXT: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr %[[C_RELOAD]], i64 4 + // CHECK-NOSANITIZE-NEXT: br label %[[CAST_END]] + // CHECK-SANITIZE-NEXT: %[[PTRTOINT:.*]] = ptrtoint %struct.C* %[[C_RELOAD]] to i64 + // CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRTOINT]], 3 + // CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:[^,]+]], label %[[HANDLER_TYPE_MISMATCH:[^,]+]] + // CHECK-SANITIZE: [[HANDLER_TYPE_MISMATCH]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort( + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_type_mismatch_v1( + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.ubsantrap( + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable + // CHECK-SANITIZE: [[CONT]]: + // CHECK-SANITIZE-NEXT: %[[CONT_BITCAST:.*]] = bitcast %struct.C* %0 to i8* + // CHECK-SANITIZE-NEXT: %[[ADD_PTR:.*]] = getelementptr inbounds i8, i8* %[[CONT_BITCAST]], i64 4 + // CHECK-SANITIZE-NEXT: %[[CONT_BITCAST1:.*]] = bitcast i8* %[[ADD_PTR]] to %struct.B* + // CHECK-SANITIZE-NEXT: br label %[[CAST_END]] + // CHECK: [[CAST_END]]: + // CHECK-NOSANITIZE-NEXT: %[[CAST_RESULT:.*]] = phi %struct.B* [ %[[CONT_BITCAST1]], %[[CAST_NOT_NULL]] ], [ null, %[[ENTRY]] ] + // CHECK-NOSANITIZE-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr %[[CAST_RESULT]], i64 8) ] + // CHECK-NOSANITIZE-NEXT: ret ptr %[[CAST_RESULT]] + // CHECK-NOSANITIZE-NEXT: } + // CHECK-SANITIZE-NEXT: %[[CAST_RESULT:.*]] = phi %struct.B* [ %[[CONT_BITCAST1]], %[[CONT]] ], [ null, %[[ENTRY]] ] + // CHECK-SANITIZE-NEXT: %[[CAST_RESULT1:.*]] = bitcast %struct.B* %[[CAST_RESULT]] to i8* + // CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[CAST_RESULT1]] to i64 + // CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 7 + // CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0 + // CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[CAST_RESULT1]] to i64 + // CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT1:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} + // CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]: + // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* {{.*}}@[[LINE_100_ALIGNMENT_ASSUMPTION]]{{.*}}, i64 %[[PTRINT_DUP]], i64 8, i64 0){{.*}} + // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* {{.*}}@[[LINE_100_ALIGNMENT_ASSUMPTION]]{{.*}}, i64 %[[PTRINT_DUP]], i64 8, i64 0){{.*}} + // CHECK-SANITIZE-TRAP-NEXT: call void @llvm.ubsantrap(i8 23){{.*}} + // CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable + // CHECK-SANITIZE: [[CONT1]]: + // CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* %[[CAST_RESULT1]], i64 8) ] + // CHECK-SANITIZE-NEXT: ret i8* %[[CAST_RESULT1]] + // CHECK-SANITIZE-NEXT: } +#line 100 + return __builtin_assume_aligned((B*)c, 8); +}