diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -100,8 +100,8 @@ by Clang (and by ISO/IEC/IEEE 60559 / IEEE 754) as producing either an infinity or NaN value, so is not included in ``-fsanitize=undefined``. - ``-fsanitize=function``: Indirect call of a function through a - function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64 - only). + function pointer of the wrong type (Darwin/Linux, C++ and + AArch64/x86-32/x86-64 only). - ``-fsanitize=implicit-unsigned-integer-truncation``, ``-fsanitize=implicit-signed-integer-truncation``: Implicit conversion from integer of larger bit width to smaller bit width, if that results in data diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5644,6 +5644,12 @@ } return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty); } + + llvm::Constant * + getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { + // b .+8 + return llvm::ConstantInt::get(CGM.Int32Ty, 0x14000002); + } }; class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo { diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -483,9 +483,8 @@ Res |= SanitizerKind::Leak; Res |= SanitizerKind::Thread; } - if (IsX86 || IsX86_64) { + if (IsAArch64 || IsX86 || IsX86_64) Res |= SanitizerKind::Function; - } if (IsAArch64 || IsX86 || IsX86_64) { Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Fuzzer; diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -771,7 +771,7 @@ Res |= SanitizerKind::Thread; if (IsX86_64) Res |= SanitizerKind::KernelMemory; - if (IsX86 || IsX86_64) + if (IsAArch64 || IsX86 || IsX86_64) Res |= SanitizerKind::Function; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || IsPowerPC64 || IsHexagon || IsLoongArch64 || IsRISCV64) diff --git a/clang/test/CodeGen/ubsan-function.cpp b/clang/test/CodeGen/ubsan-function.cpp --- a/clang/test/CodeGen/ubsan-function.cpp +++ b/clang/test/CodeGen/ubsan-function.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,X86 +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,AARCH64 +// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,AARCH64 // CHECK: @[[PROXY:.*]] = private unnamed_addr constant ptr @_ZTIFvvE // CHECK: define{{.*}} void @_Z3funv() #0 !func_sanitize ![[FUNCSAN:.*]] { @@ -7,7 +9,8 @@ // CHECK-LABEL: define{{.*}} void @_Z6callerPFvvE(ptr noundef %f) // CHECK: getelementptr <{ i32, i32 }>, ptr {{.*}}, i32 -1, i32 0, !nosanitize // CHECK: load i32, ptr {{.*}}, align {{.*}}, !nosanitize -// CHECK: icmp eq i32 {{.*}}, 846595819, !nosanitize +// X86-NEXT: icmp eq i32 {{.*}}, 846595819, !nosanitize +// AARCH64-NEXT: icmp eq i32 {{.*}}, 335544322, !nosanitize // CHECK: br i1 {{.*}}, label %[[LABEL1:.*]], label %[[LABEL4:.*]], !nosanitize // CHECK: [[LABEL1]]: // CHECK: getelementptr <{ i32, i32 }>, ptr {{.*}}, i32 -1, i32 1, !nosanitize @@ -22,4 +25,7 @@ // CHECK: br label %[[LABEL4]], !nosanitize void caller(void (*f)()) { f(); } -// CHECK: ![[FUNCSAN]] = !{i32 846595819, ptr @[[PROXY]]} +// X86: ![[FUNCSAN]] = !{i32 846595819, ptr @[[PROXY]]} + +/// .word 0x14000002 # b .+8 +// AARCH64: ![[FUNCSAN]] = !{i32 335544322, ptr @[[PROXY]]} diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -525,9 +525,10 @@ // RUN: %clang --target=x86_64-linux-gnu -fsanitize=thread -fsanitize-thread-atomics -fno-sanitize-thread-atomics %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-ATOMICS-BOTH-OFF // CHECK-TSAN-ATOMICS-BOTH-OFF: -cc1{{.*}}tsan-instrument-atomics=0 -// RUN: %clang --target=x86_64-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-DARWIN -// RUN: %clang --target=i386-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-DARWIN -// CHECK-FSAN-DARWIN: -cc1{{.*}}"-fsanitize=function" "-fsanitize-recover=function" +// RUN: %clang --target=x86_64-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FUNCTION +// RUN: %clang --target=i386-apple-darwin10 -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FUNCTION +// RUN: %clang --target=aarch64-unknown-linux-gnu -fsanitize=function %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FUNCTION +// CHECK-FUNCTION: -cc1{{.*}}"-fsanitize=function" "-fsanitize-recover=function" // RUN: %clang --target=x86_64-apple-darwin10 -mmacosx-version-min=10.8 -fsanitize=vptr %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-DARWIN-OLD // CHECK-VPTR-DARWIN-OLD: unsupported option '-fsanitize=vptr' for target 'x86_64-apple-darwin10' diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg.py b/compiler-rt/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg.py --- a/compiler-rt/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg.py +++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg.py @@ -1,3 +1,3 @@ -# The function type checker is only supported on x86 and x86_64 for now. -if config.target_arch not in ['x86', 'x86_64']: +# The function type checker is only supported on aarch64 and x86 for now. +if config.target_arch not in ['aarch64', 'x86', 'x86_64']: config.unsupported = True diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -972,7 +972,7 @@ // Emit the function prologue data for the indirect call sanitizer. if (const MDNode *MD = F.getMetadata(LLVMContext::MD_func_sanitize)) { - assert(TM.getTargetTriple().isX86()); + assert(TM.getTargetTriple().isAArch64() || TM.getTargetTriple().isX86()); assert(MD->getNumOperands() == 2); auto *PrologueSig = mdconst::extract(MD->getOperand(0)); diff --git a/llvm/test/CodeGen/AArch64/func-sanitizer.ll b/llvm/test/CodeGen/AArch64/func-sanitizer.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/func-sanitizer.ll @@ -0,0 +1,22 @@ +; RUN: llc -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s + +; CHECK-LABEL: .type _Z3funv,@function +; CHECK-NEXT: .word 335544322 // 0x14000002 +; CHECK-NEXT: .word .L__llvm_rtti_proxy-_Z3funv +; CHECK-NEXT: _Z3funv: +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: ret + +; CHECK: .section .rodata,"a",@progbits +; CHECK-LABEL: .L__llvm_rtti_proxy: +; CHECK-NEXT: .xword _ZTIFvvE +; CHECK-NEXT: .size .L__llvm_rtti_proxy, 8 + +@_ZTIFvvE = linkonce_odr constant i32 1 +@__llvm_rtti_proxy = private unnamed_addr constant ptr @_ZTIFvvE + +define dso_local void @_Z3funv() nounwind !func_sanitize !0 { + ret void +} + +!0 = !{i32 335544322, ptr @__llvm_rtti_proxy} diff --git a/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll b/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll --- a/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll +++ b/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll @@ -1,5 +1,8 @@ ; RUN: llc -mtriple=aarch64 %s -o - | FileCheck %s +@_ZTIFvvE = linkonce_odr constant i32 2 +@__llvm_rtti_proxy = private unnamed_addr constant ptr @_ZTIFvvE + define void @f0() "patchable-function-entry"="0" "branch-target-enforcement"="true" { ; CHECK-LABEL: f0: ; CHECK-NEXT: .Lfunc_begin0: @@ -85,3 +88,22 @@ call void asm sideeffect "", ""() ret void } + +;; Test the interaction with -fsanitize=function. +; CHECK: .type sanitize_function,@function +; CHECK-NEXT: .Ltmp{{.*}}: +; CHECK-NEXT: nop +; CHECK-NEXT: .word 335544322 // 0x14000002 +; CHECK-NEXT: .word .L__llvm_rtti_proxy-sanitize_function +; CHECK-NEXT: sanitize_function: +; CHECK-NEXT: .Lfunc_begin{{.*}}: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: hint #34 +; CHECK-NEXT: nop +; CHECK-NEXT: ret +define void @sanitize_function(ptr noundef %x) "patchable-function-prefix"="1" "patchable-function-entry"="1" "branch-target-enforcement"="true" !func_sanitize !0 { + ret void +} + +!0 = !{i32 335544322, ptr @__llvm_rtti_proxy}