1 // RUN: %cheri_cc1 -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-HYBRID
2 // RUN: %cheri_purecap_cc1 -mllvm -cheri-cap-table-abi=pcrel -emit-llvm %s -o - | %cheri_FileCheck %s -check-prefixes CHECK-PURECAP
3 // RUN: %cheri_cc1 -S %s -o - | FileCheck %s -check-prefix HYBRID-ASM
4 // RUN: %cheri_purecap_cc1 -S %s -o - | %cheri_FileCheck %s -check-prefix PURECAP-ASM
5 // RUN: %cheri_purecap_cc1 -S %s -o - | %cheri_FileCheck %s -check-prefix PURECAP-ASM
6 
7 // We were miscompiling qhooks.cpp from QtBase: even in the purecap ABI we
8 // were emitting .8byte directives for the qtHookData members instead of
9 // capability sized elements. Because of this the qtHookData symbol only
10 // had a size of 7*8 which resulted in length violations on access for
11 // CHERI256 when trying to read the RemoveQObject hook.
12 
13 typedef __UINTPTR_TYPE__ quintptr;
14 
15 #define QT_VERSION 0x051000
16 namespace QHooks {
17 enum HookIndex {
18     HookDataVersion = 0,
19     HookDataSize = 1,
20     QtVersion = 2,
21     AddQObject = 3,
22     RemoveQObject = 4,
23     Startup = 5,
24     TypeInformationVersion = 6,
25     LastHookIndex
26 };
27 }
28 quintptr qtHookData[] = {
29     3, // hook data version
30     QHooks::LastHookIndex, // size of qtHookData
31     QT_VERSION,
32     0,
33     0,
34     0,
35     16
36 };
37 
38 // CHECK-HYBRID: @qtHookData = global [7 x i64] [i64 3, i64 7, i64 331776, i64 0, i64 0, i64 0, i64 16], align 8
39 // CHECK-PURECAP: @qtHookData = addrspace(200) global [7 x i8 addrspace(200)*]
40 // CHECK-PURECAP-SAME: [i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 3),
41 // CHECK-PURECAP-SAME:  i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 7),
42 // CHECK-PURECAP-SAME:  i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 331776),
43 // CHECK-PURECAP-SAME:  i8 addrspace(200)* null, i8 addrspace(200)* null, i8 addrspace(200)* null,
44 // CHECK-PURECAP-SAME:  i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 16)], align [[#CAP_SIZE]]
45 
46 // HYBRID-ASM-LABEL: qtHookData:
47 // HYBRID-ASM-NEXT: 	.8byte	3
48 // HYBRID-ASM-NEXT: 	.8byte	7
49 // HYBRID-ASM-NEXT: 	.8byte	331776
50 // HYBRID-ASM-NEXT: 	.8byte	0
51 // HYBRID-ASM-NEXT: 	.8byte	0
52 // HYBRID-ASM-NEXT: 	.8byte	0
53 // HYBRID-ASM-NEXT: 	.8byte	16
54 // HYBRID-ASM-NEXT: 	.size	qtHookData, 56
55 
56 // PURECAP-ASM-LABEL: qtHookData:
57 // PURECAP-ASM-NEXT: 	.chericap	3
58 // PURECAP-ASM-NEXT: 	.chericap	7
59 // PURECAP-ASM-NEXT: 	.chericap	331776
60 // PURECAP-ASM-NEXT: 	.chericap	0
61 // PURECAP-ASM-NEXT: 	.chericap	0
62 // PURECAP-ASM-NEXT: 	.chericap	0
63 // PURECAP-ASM-NEXT: 	.chericap	16
64 // PURECAP-ASM-NEXT: 	.size	qtHookData, [[#CAP_SIZE * 7]]
65 
66 
67 // Some sanity check that this is actually a codegen problem and not a Sema one@
68 static_assert(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]), "");
69 static_assert(sizeof(void*) == sizeof(qtHookData[0]), "");
70 static_assert(sizeof(qtHookData) == QHooks::LastHookIndex * sizeof(void*), "");
71 
72 #ifdef __CHERI_PURE_CAPABILITY__
73 static_assert(sizeof(quintptr) == sizeof(void*), "");
74 static_assert(sizeof(quintptr) == sizeof(__uintcap_t), "");
75 #else
76 static_assert(sizeof(quintptr) == sizeof(long), "");
77 #endif
78 
79 
80 // Check that it also works with an array filler
81 quintptr array2[4] = {
82   42, (quintptr)&array2,
83 };
84 
85 // CHECK-HYBRID: @array2 = global [4 x i64] [i64 42, i64 ptrtoint ([4 x i64]* @array2 to i64), i64 0, i64 0], align 8
86 // HYBRID-ASM-LABEL: array2:
87 // HYBRID-ASM-NEXT:	.8byte	42
88 // HYBRID-ASM-NEXT:	.8byte	array2
89 // HYBRID-ASM-NEXT:	.8byte	0
90 // HYBRID-ASM-NEXT:	.8byte	0
91 // HYBRID-ASM-NEXT:	.size	array2, 32
92 
93 // CHECK-PURECAP: @array2 = addrspace(200) global [4 x i8 addrspace(200)*]
94 // CHECK-PURECAP-SAME: [i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 42),
95 // CHECK-PURECAP-SAME:  i8 addrspace(200)* bitcast ([4 x i8 addrspace(200)*] addrspace(200)* @array2 to i8 addrspace(200)*),
96 // CHECK-PURECAP-SAME:  i8 addrspace(200)* null,
97 // CHECK-PURECAP-SAME:  i8 addrspace(200)* null], align [[#CAP_SIZE]]
98 // PURECAP-ASM-LABEL: array2:
99 // PURECAP-ASM-NEXT:	.chericap	42
100 // PURECAP-ASM-NEXT:	.chericap	array2
101 // PURECAP-ASM-NEXT:	.chericap	0
102 // PURECAP-ASM-NEXT:	.chericap	0
103 // PURECAP-ASM-NEXT: 	.size	array2, [[#CAP_SIZE * 4]]
104 
105 // Check arrays with run-time initializers:
106 quintptr extern_func();
107 
108 quintptr array3[4] = {
109   0,
110   extern_func(),
111   (quintptr)&extern_func,
112   1234567
113 };
114 
115 // CHECK-HYBRID: @array3 = global [4 x i64] zeroinitializer, align 8
116 // CHECK-HYBRID: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_qhooks_array.cpp, i8* null }]
117 // HYBRID-ASM-LABEL: array3:
118 // HYBRID-ASM-NEXT:	.space	32
119 // HYBRID-ASM-NEXT:	.size	array3, 32
120 
121 // CHECK-PURECAP: @array3 = addrspace(200) global [4 x i8 addrspace(200)*] zeroinitializer, align [[#CAP_SIZE]]
122 // CHECK-PURECAP: @llvm.global_ctors = appending addrspace(200) global [1 x { i32, void () addrspace(200)*, i8 addrspace(200)* }] [{ i32, void () addrspace(200)*, i8 addrspace(200)* }
123 // CHECK-PURECAP-SAME: { i32 65535, void () addrspace(200)* @_GLOBAL__sub_I_qhooks_array.cpp, i8 addrspace(200)* null }]
124 // PURECAP-ASM-LABEL: array3:
125 // PURECAP-ASM-NEXT:	.space	[[#CAP_SIZE * 4]]
126 // PURECAP-ASM-NEXT: 	.size	array3, [[#CAP_SIZE * 4]]
127