llvm::Value *CalleePtr = Callee.getFunctionPointer();
+ // On 32-bit Arm, the low bit of a function pointer indicates whether
+ // it's using the Arm or Thumb instruction set. The actual first
+ // instruction lives at the same address either way, so we must clear
+ // that low bit before using the function address to find the prefix
+ // structure.
+ //
+ // This applies to both Arm and Thumb target triples, because
+ // either one could be used in an interworking context where it
+ // might be passed function pointers of both types.
+ llvm::Value *AlignedCalleePtr;
+ if (CGM.getTriple().isARM() || CGM.getTriple().isThumb()) {
+ llvm::Value *CalleeAddress =
+ Builder.CreatePtrToInt(CalleePtr, IntPtrTy);
+ llvm::Value *Mask = llvm::ConstantInt::get(IntPtrTy, ~1);
+ llvm::Value *AlignedCalleeAddress =
+ Builder.CreateAnd(CalleeAddress, Mask);
+ AlignedCalleePtr =
+ Builder.CreateIntToPtr(AlignedCalleeAddress, CalleePtr->getType());
+ } else {
+ AlignedCalleePtr = CalleePtr;
+ }
+
llvm::Value *CalleePrefixStruct = Builder.CreateBitCast(
- CalleePtr, llvm::PointerType::getUnqual(PrefixStructTy));
+ AlignedCalleePtr, llvm::PointerType::getUnqual(PrefixStructTy));
llvm::Value *CalleeSigPtr =
Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, -1, 0);
llvm::Value *CalleeSig =
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s
-// RUN: %clang_cc1 -triple aarch64_be-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,64
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,64
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,64
+// RUN: %clang_cc1 -triple arm-none-eabi -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,ARM,32
// CHECK: define{{.*}} void @_Z3funv() #0 !func_sanitize ![[FUNCSAN:.*]] {
void fun() {}
// CHECK-LABEL: define{{.*}} void @_Z6callerPFvvE(ptr noundef %f)
+// ARM: ptrtoint ptr {{.*}} to i32, !nosanitize !5
+// ARM: and i32 {{.*}}, -2, !nosanitize !5
+// ARM: inttoptr i32 {{.*}} to ptr, !nosanitize !5
// CHECK: getelementptr <{ i32, i32 }>, ptr {{.*}}, i32 -1, i32 0, !nosanitize
// CHECK: load i32, ptr {{.*}}, align {{.*}}, !nosanitize
// CHECK: icmp eq i32 {{.*}}, -1056584962, !nosanitize
// CHECK: icmp eq i32 {{.*}}, -1522505972, !nosanitize
// CHECK: br i1 {{.*}}, label %[[LABEL3:.*]], label %[[LABEL2:[^,]*]], {{.*}}!nosanitize
// CHECK: [[LABEL2]]:
-// CHECK: call void @__ubsan_handle_function_type_mismatch_abort(ptr @[[#]], i64 %[[#]]) #[[#]], !nosanitize
+// 64: call void @__ubsan_handle_function_type_mismatch_abort(ptr @[[#]], i64 %[[#]]) #[[#]], !nosanitize
+// 32: call void @__ubsan_handle_function_type_mismatch_abort(ptr @[[#]], i32 %[[#]]) #[[#]], !nosanitize
// CHECK-NEXT: unreachable, !nosanitize
// CHECK-EMPTY:
// CHECK-NEXT: [[LABEL3]]: