Skip to content

Commit 20d6dee

Browse files
committed
-fsanitize=function: fix alignment fault on Arm targets.
Function pointers are checked by loading a prefix structure from just before the function's entry point. However, on Arm, the function pointer is not always exactly equal to the address of the entry point, because Thumb function pointers have the low bit set to tell the BX instruction to enter them in Thumb state. So the generated code loads from an odd address and suffers an alignment fault. Fixed by clearing the low bit of the function pointer before subtracting 8. Differential Revision: https://reviews.llvm.org/D151308
1 parent d2502eb commit 20d6dee

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5364,8 +5364,30 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
53645364

53655365
llvm::Value *CalleePtr = Callee.getFunctionPointer();
53665366

5367+
// On 32-bit Arm, the low bit of a function pointer indicates whether
5368+
// it's using the Arm or Thumb instruction set. The actual first
5369+
// instruction lives at the same address either way, so we must clear
5370+
// that low bit before using the function address to find the prefix
5371+
// structure.
5372+
//
5373+
// This applies to both Arm and Thumb target triples, because
5374+
// either one could be used in an interworking context where it
5375+
// might be passed function pointers of both types.
5376+
llvm::Value *AlignedCalleePtr;
5377+
if (CGM.getTriple().isARM() || CGM.getTriple().isThumb()) {
5378+
llvm::Value *CalleeAddress =
5379+
Builder.CreatePtrToInt(CalleePtr, IntPtrTy);
5380+
llvm::Value *Mask = llvm::ConstantInt::get(IntPtrTy, ~1);
5381+
llvm::Value *AlignedCalleeAddress =
5382+
Builder.CreateAnd(CalleeAddress, Mask);
5383+
AlignedCalleePtr =
5384+
Builder.CreateIntToPtr(AlignedCalleeAddress, CalleePtr->getType());
5385+
} else {
5386+
AlignedCalleePtr = CalleePtr;
5387+
}
5388+
53675389
llvm::Value *CalleePrefixStruct = Builder.CreateBitCast(
5368-
CalleePtr, llvm::PointerType::getUnqual(PrefixStructTy));
5390+
AlignedCalleePtr, llvm::PointerType::getUnqual(PrefixStructTy));
53695391
llvm::Value *CalleeSigPtr =
53705392
Builder.CreateConstGEP2_32(PrefixStructTy, CalleePrefixStruct, -1, 0);
53715393
llvm::Value *CalleeSig =

clang/test/CodeGen/ubsan-function.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s
2-
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s
3-
// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s
1+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,64
2+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,64
3+
// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,64
4+
// RUN: %clang_cc1 -triple arm-none-eabi -emit-llvm -o - %s -fsanitize=function -fno-sanitize-recover=all | FileCheck %s --check-prefixes=CHECK,ARM,32
45

56
// CHECK: define{{.*}} void @_Z3funv() #0 !func_sanitize ![[FUNCSAN:.*]] {
67
void fun() {}
78

89
// CHECK-LABEL: define{{.*}} void @_Z6callerPFvvE(ptr noundef %f)
10+
// ARM: ptrtoint ptr {{.*}} to i32, !nosanitize !5
11+
// ARM: and i32 {{.*}}, -2, !nosanitize !5
12+
// ARM: inttoptr i32 {{.*}} to ptr, !nosanitize !5
913
// CHECK: getelementptr <{ i32, i32 }>, ptr {{.*}}, i32 -1, i32 0, !nosanitize
1014
// CHECK: load i32, ptr {{.*}}, align {{.*}}, !nosanitize
1115
// CHECK: icmp eq i32 {{.*}}, -1056584962, !nosanitize
@@ -16,7 +20,8 @@ void fun() {}
1620
// CHECK: icmp eq i32 {{.*}}, -1522505972, !nosanitize
1721
// CHECK: br i1 {{.*}}, label %[[LABEL3:.*]], label %[[LABEL2:[^,]*]], {{.*}}!nosanitize
1822
// CHECK: [[LABEL2]]:
19-
// CHECK: call void @__ubsan_handle_function_type_mismatch_abort(ptr @[[#]], i64 %[[#]]) #[[#]], !nosanitize
23+
// 64: call void @__ubsan_handle_function_type_mismatch_abort(ptr @[[#]], i64 %[[#]]) #[[#]], !nosanitize
24+
// 32: call void @__ubsan_handle_function_type_mismatch_abort(ptr @[[#]], i32 %[[#]]) #[[#]], !nosanitize
2025
// CHECK-NEXT: unreachable, !nosanitize
2126
// CHECK-EMPTY:
2227
// CHECK-NEXT: [[LABEL3]]:

0 commit comments

Comments
 (0)