Skip to content

Commit f5fa52a

Browse files
committed
Add fn ptr type discrimination tests
1 parent 8117cf6 commit f5fa52a

10 files changed

Lines changed: 2024 additions & 0 deletions
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
//@ add-minicore
2+
// ignore-tidy-linelength
3+
//@ only-pauthtest
4+
// Run it at O0, so that the compiler doesn't optimise the calls away.
5+
//@ revisions: DISC NO_DISC
6+
7+
//@ [DISC] needs-llvm-components: aarch64
8+
//@ [DISC] compile-flags: --target=aarch64-unknown-linux-pauthtest --crate-type=lib -Zpointer-authentication=+function-pointer-type-discrimination -C opt-level=0
9+
//@ [NO_DISC] needs-llvm-components: aarch64
10+
//@ [NO_DISC] compile-flags: --target=aarch64-unknown-linux-pauthtest --crate-type=lib -Zpointer-authentication=-function-pointer-type-discrimination -C opt-level=0
11+
12+
// Test generation of function-pointer type discriminators. The discriminator values were obtained
13+
// from Clang by compiling equivalent C code (included). Both compilers must generate identical
14+
// values.
15+
//
16+
// Make sure that the compiler can see through chains of nested structs, both when used as globals,
17+
// arguments and returns.
18+
//
19+
// Equivalent C:
20+
//
21+
// #include <stdio.h>
22+
//
23+
// typedef int (*L0)(int);
24+
// typedef int (*L1)(L0);
25+
// typedef int (*L2)(L1);
26+
// typedef int (*L3)(L2);
27+
// typedef int (*L4)(L3);
28+
// typedef L0 (*DeepRet)(void);
29+
//
30+
// int callback_i32(int x) { return x + 1; }
31+
//
32+
// int dummy_l1(L0 cb) { return cb(5); }
33+
// int dummy_l2(L1 cb) { return cb(callback_i32); }
34+
// int dummy_l3(L2 cb) { return cb(dummy_l1); }
35+
// int dummy_l4(L3 cb) { return cb(dummy_l2); }
36+
//
37+
// L0 returned_fn(void) { return callback_i32; }
38+
//
39+
// DeepRet f_deep(L4 cb) {
40+
// cb(dummy_l3);
41+
// return returned_fn;
42+
// }
43+
//
44+
// DeepRet (*T_DEEP)(L4) = f_deep;
45+
//
46+
// int main(void) {
47+
// DeepRet ret_fn;
48+
// L0 inner_fn;
49+
// int result;
50+
//
51+
// ret_fn = T_DEEP(dummy_l4);
52+
// inner_fn = ret_fn();
53+
// result = inner_fn(42);
54+
//
55+
// printf("result = %d\n", result);
56+
//
57+
// return 0;
58+
// }
59+
60+
#![feature(no_core, lang_items)]
61+
#![no_std]
62+
#![no_core]
63+
#![crate_type = "lib"]
64+
extern crate minicore;
65+
use minicore::hint::black_box;
66+
67+
// Nested fn ptr chain.
68+
type L0 = extern "C" fn(i32) -> i32;
69+
type L1 = extern "C" fn(L0) -> i32;
70+
type L2 = extern "C" fn(L1) -> i32;
71+
type L3 = extern "C" fn(L2) -> i32;
72+
type L4 = extern "C" fn(L3) -> i32;
73+
// Function returning fn ptr.
74+
type DeepRet = extern "C" fn() -> L0;
75+
76+
#[used]
77+
// DISC: @{{.*}}T_DEEP = constant ptr ptrauth (ptr @{{.*}}f_deep, i32 0, i64 1059), align 8
78+
// NO_DISC: @{{.*}}T_DEEP = constant ptr ptrauth (ptr @{{.*}}f_deep, i32 0), align 8
79+
static T_DEEP: unsafe extern "C" fn(L4) -> DeepRet = f_deep;
80+
81+
// Leaf callback.
82+
// CHECK-LABEL: callback_i32
83+
pub extern "C" fn callback_i32(x: i32) -> i32 {
84+
x
85+
}
86+
87+
// Dummy chain impl.
88+
// CHECK-LABEL: dummy_l1
89+
// CHECK: (ptr [[CB:%.*]])
90+
pub extern "C" fn dummy_l1(cb: L0) -> i32 {
91+
// DISC: call i32 [[CB]](i32 5) {{.*}} [ "ptrauth"(i32 0, i64 2981) ]
92+
// NO_DISC: call i32 [[CB]](i32 5) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
93+
cb(5)
94+
}
95+
// CHECK-LABEL: dummy_l2
96+
// CHECK: (ptr [[CB:%.*]])
97+
pub extern "C" fn dummy_l2(cb: L1) -> i32 {
98+
// DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}callback_i32, i32 0, i64 2981)) {{.*}} [ "ptrauth"(i32 0, i64 12410) ]
99+
// NO_DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}callback_i32, i32 0)) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
100+
cb(callback_i32)
101+
}
102+
// CHECK-LABEL: dummy_l3
103+
// CHECK: (ptr [[CB:%.*]])
104+
pub extern "C" fn dummy_l3(cb: L2) -> i32 {
105+
// DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}dummy_l1, i32 0, i64 12410)) {{.*}} [ "ptrauth"(i32 0, i64 12410) ]
106+
// NO_DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}dummy_l1, i32 0)) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
107+
cb(dummy_l1)
108+
}
109+
// CHECK-LABEL: dummy_l4
110+
// CHECK: (ptr [[CB:%.*]])
111+
pub extern "C" fn dummy_l4(cb: L3) -> i32 {
112+
// DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}dummy_l2, i32 0, i64 12410)) {{.*}} [ "ptrauth"(i32 0, i64 12410) ]
113+
// NO_DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}dummy_l2, i32 0)) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
114+
cb(dummy_l2)
115+
}
116+
// Return fn impl.
117+
// CHECK-LABEL: returned_fn
118+
pub extern "C" fn returned_fn() -> L0 {
119+
// DISC: ret ptr ptrauth (ptr @{{.*}}callback_i32, i32 0, i64 2981)
120+
// NO_DISC: ret ptr ptrauth (ptr @{{.*}}callback_i32, i32 0)
121+
return callback_i32;
122+
}
123+
// Entry point to the chain, takes L4 and returns function returning fn ptr.
124+
// CHECK-LABEL: f_deep
125+
// CHECK: (ptr [[CB:%.*]])
126+
pub extern "C" fn f_deep(cb: L4) -> DeepRet {
127+
// DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}dummy_l3, i32 0, i64 12410)) {{.*}} [ "ptrauth"(i32 0, i64 12410) ]
128+
// NO_DISC: call i32 [[CB]](ptr ptrauth (ptr @{{.*}}dummy_l3, i32 0)) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
129+
cb(dummy_l3);
130+
// DISC: ret ptr ptrauth (ptr @{{.*}}returned_fn, i32 0, i64 34128)
131+
// NO_DISC: ret ptr ptrauth (ptr @{{.*}}returned_fn, i32 0)
132+
return returned_fn;
133+
}
134+
135+
// CHECK-LABEL: main
136+
pub fn main() {
137+
unsafe {
138+
// DISC: [[RET_FN:%.*]] = call ptr ptrauth (ptr @{{.*}}f_deep, i32 0, i64 1059)(ptr ptrauth (ptr @{{.*}}dummy_l4, i32 0, i64 12410)) {{.*}} [ "ptrauth"(i32 0, i64 1059) ]
139+
// NO_DISC: [[RET_FN:%.*]] = call ptr ptrauth (ptr @{{.*}}f_deep, i32 0)(ptr ptrauth (ptr @{{.*}}dummy_l4, i32 0)) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
140+
let ret_fn: DeepRet = T_DEEP(dummy_l4);
141+
// DISC: [[INNER_FN:%.*]] = call ptr [[RET_FN]]() {{.*}} [ "ptrauth"(i32 0, i64 34128) ]
142+
// NO_DISC: [[INNER_FN:%.*]] = call ptr [[RET_FN]]() {{.*}} [ "ptrauth"(i32 0, i64 0) ]
143+
let inner_fn: L0 = ret_fn();
144+
// DISC: call i32 [[INNER_FN]](i32 42) {{.*}} [ "ptrauth"(i32 0, i64 2981) ]
145+
// NO_DISC: call i32 [[INNER_FN]](i32 42) {{.*}} [ "ptrauth"(i32 0, i64 0) ]
146+
let result = inner_fn(42);
147+
148+
black_box(result);
149+
}
150+
}

0 commit comments

Comments
 (0)