// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \ // RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC %s // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \ // RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefix=CHECK %s // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-pch %s -o %t.ast // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ // RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC %s // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \ // RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC %s // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \ // RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefix=CHECK %s // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-pch %s -o %t.ast // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \ // RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC %s #ifdef __cplusplus extern "C" { #endif void f(void); void f2(int); void (*fnptr)(void); void *opaque; unsigned long uintptr; // CHECK: @test_constant_null = global ptr null void (*test_constant_null)(int) = 0; // CHECK: @test_constant_cast = global ptr ptrauth (ptr @f, i32 0, i64 2712) void (*test_constant_cast)(int) = (void (*)(int))f; #ifndef __cplusplus // CHECKC: @enum_func_ptr = global ptr ptrauth (ptr @enum_func, i32 0, i64 2712) enum Enum0; void enum_func(enum Enum0); void (*enum_func_ptr)(enum Enum0) = enum_func; #endif // CHECK: @test_opaque = global ptr ptrauth (ptr @f, i32 0) void *test_opaque = #ifdef __cplusplus (void *) #endif (void (*)(int))(double (*)(double))f; // CHECK: @test_intptr_t = global i64 ptrtoint (ptr ptrauth (ptr @f, i32 0) to i64) unsigned long test_intptr_t = (unsigned long)f; // CHECK: @test_through_long = global ptr ptrauth (ptr @f, i32 0, i64 2712) void (*test_through_long)(int) = (void (*)(int))(long)f; // CHECK: @test_to_long = global i64 ptrtoint (ptr ptrauth (ptr @f, i32 0) to i64) long test_to_long = (long)(double (*)())f; extern void external_function(void); // CHECK: @fptr1 = global ptr ptrauth (ptr @external_function, i32 0, i64 18983) void (*fptr1)(void) = external_function; // CHECK: @fptr2 = global ptr ptrauth (ptr @external_function, i32 0, i64 18983) void (*fptr2)(void) = &external_function; // CHECK: @fptr3 = global ptr ptrauth (ptr @external_function, i32 2, i64 26) void (*fptr3)(void) = __builtin_ptrauth_sign_constant(&external_function, 2, 26); // CHECK: @fptr4 = global ptr ptrauth (ptr @external_function, i32 2, i64 26, ptr @fptr4) void (*fptr4)(void) = __builtin_ptrauth_sign_constant(&external_function, 2, __builtin_ptrauth_blend_discriminator(&fptr4, 26)); // CHECK-LABEL: define{{.*}} void @test_call() void test_call() { // CHECK: [[T0:%.*]] = load ptr, ptr @fnptr, // CHECK-NEXT: call void [[T0]]() [ "ptrauth"(i32 0, i64 18983) ] fnptr(); } // CHECK-LABEL: define{{.*}} ptr @test_function_pointer() // CHECK: ret ptr ptrauth (ptr @external_function, i32 0, i64 18983) void (*test_function_pointer())(void) { return external_function; } struct InitiallyIncomplete; extern struct InitiallyIncomplete returns_initially_incomplete(void); // CHECK-LABEL: define{{.*}} void @use_while_incomplete() void use_while_incomplete() { // CHECK: [[VAR:%.*]] = alloca ptr, // CHECK-NEXT: store ptr ptrauth (ptr @returns_initially_incomplete, i32 0, i64 25106), ptr [[VAR]] struct InitiallyIncomplete (*fnptr)(void) = &returns_initially_incomplete; } struct InitiallyIncomplete { int x; }; // CHECK-LABEL: define{{.*}} void @use_while_complete() void use_while_complete() { // CHECK: [[VAR:%.*]] = alloca ptr, // CHECK-NEXT: store ptr ptrauth (ptr @returns_initially_incomplete, i32 0, i64 25106), ptr [[VAR]] // CHECK-NEXT: ret void struct InitiallyIncomplete (*fnptr)(void) = &returns_initially_incomplete; } #ifndef __cplusplus void knr(param) int param; {} // CHECKC-LABEL: define{{.*}} void @test_knr void test_knr() { void (*p)() = knr; p(0); // CHECKC: [[P:%.*]] = alloca ptr // CHECKC: store ptr ptrauth (ptr @knr, i32 0, i64 18983), ptr [[P]] // CHECKC: [[LOAD:%.*]] = load ptr, ptr [[P]] // CHECKC: call void [[LOAD]](i32 noundef 0) [ "ptrauth"(i32 0, i64 18983) ] } // CHECKC-LABEL: define{{.*}} void @test_redeclaration void test_redeclaration() { void redecl(); void (*ptr)() = redecl; void redecl(int); void (*ptr2)(int) = redecl; ptr(); ptr2(0); // CHECKC: store ptr ptrauth (ptr @redecl, i32 0, i64 18983), ptr %ptr // CHECKC: store ptr ptrauth (ptr @redecl, i32 0, i64 2712), ptr %ptr2 // CHECKC: call void {{.*}}() [ "ptrauth"(i32 0, i64 18983) ] // CHECKC: call void {{.*}}(i32 noundef 0) [ "ptrauth"(i32 0, i64 2712) ] } void knr2(param) int param; {} // CHECKC-LABEL: define{{.*}} void @test_redecl_knr void test_redecl_knr() { void (*p)() = knr2; p(); // CHECKC: store ptr ptrauth (ptr @knr2, i32 0, i64 18983) // CHECKC: call void {{.*}}() [ "ptrauth"(i32 0, i64 18983) ] void knr2(int); void (*p2)(int) = knr2; p2(0); // CHECKC: store ptr ptrauth (ptr @knr2, i32 0, i64 2712) // CHECKC: call void {{.*}}(i32 noundef 0) [ "ptrauth"(i32 0, i64 2712) ] } #endif #ifdef __cplusplus } #endif