1 | // Test -fsanitize-address-field-padding |
2 | // RUN: echo 'type:SomeNamespace::BlacklistedByName=field-padding' > %t.type.blacklist |
3 | // RUN: echo 'src:*sanitize-address-field-padding.cpp=field-padding' > %t.file.blacklist |
4 | // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsanitize=address -fsanitize-address-field-padding=1 -fsanitize-blacklist=%t.type.blacklist -Rsanitize-address -emit-llvm -o - %s 2>&1 | FileCheck %s |
5 | // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsanitize=address -fsanitize-address-field-padding=1 -fsanitize-blacklist=%t.type.blacklist -Rsanitize-address -emit-llvm -o - %s -O1 -mconstructor-aliases 2>&1 | FileCheck %s --check-prefix=WITH_CTOR_ALIASES |
6 | // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsanitize=address -fsanitize-address-field-padding=1 -fsanitize-blacklist=%t.file.blacklist -Rsanitize-address -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=FILE_BLACKLIST |
7 | // RUN: %clang_cc1 -fsanitize=address -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=NO_PADDING |
8 | // Try to emulate -save-temps option and make sure -disable-llvm-passes will not run sanitize instrumentation. |
9 | // RUN: %clang_cc1 -fsanitize=address -emit-llvm -disable-llvm-passes -o - %s | %clang_cc1 -fsanitize=address -emit-llvm -o - -x ir | FileCheck %s --check-prefix=NO_PADDING |
10 | // |
11 | |
12 | // The reasons to ignore a particular class are not set in stone and will change. |
13 | // |
14 | // CHECK: -fsanitize-address-field-padding applied to Positive1 |
15 | // CHECK: -fsanitize-address-field-padding ignored for Negative1 because it is trivially copyable |
16 | // CHECK: -fsanitize-address-field-padding ignored for Negative2 because it is trivially copyable |
17 | // CHECK: -fsanitize-address-field-padding ignored for Negative3 because it is a union |
18 | // CHECK: -fsanitize-address-field-padding ignored for Negative4 because it is trivially copyable |
19 | // CHECK: -fsanitize-address-field-padding ignored for Negative5 because it is packed |
20 | // CHECK: -fsanitize-address-field-padding ignored for SomeNamespace::BlacklistedByName because it is blacklisted |
21 | // CHECK: -fsanitize-address-field-padding ignored for ExternCStruct because it is not C++ |
22 | // |
23 | // FILE_BLACKLIST: -fsanitize-address-field-padding ignored for Positive1 because it is in a blacklisted file |
24 | // FILE_BLACKLIST-NOT: __asan_poison_intra_object_redzone |
25 | // NO_PADDING-NOT: __asan_poison_intra_object_redzone |
26 | |
27 | |
28 | class Positive1 { |
29 | public: |
30 | Positive1() {} |
31 | ~Positive1() {} |
32 | int make_it_non_standard_layout; |
33 | private: |
34 | char private1; |
35 | int private2; |
36 | short private_array[6]; |
37 | long long private3; |
38 | }; |
39 | |
40 | Positive1 positive1; |
41 | // Positive1 with extra paddings |
42 | // CHECK: type { i32, [12 x i8], i8, [15 x i8], i32, [12 x i8], [6 x i16], [12 x i8], i64, [8 x i8] } |
43 | |
44 | struct VirtualBase { |
45 | int foo; |
46 | }; |
47 | |
48 | class ClassWithVirtualBase : public virtual VirtualBase { |
49 | public: |
50 | ClassWithVirtualBase() {} |
51 | ~ClassWithVirtualBase() {} |
52 | int make_it_non_standard_layout; |
53 | private: |
54 | char x[7]; |
55 | char y[9]; |
56 | }; |
57 | |
58 | ClassWithVirtualBase class_with_virtual_base; |
59 | |
60 | class WithFlexibleArray1 { |
61 | public: |
62 | WithFlexibleArray1() {} |
63 | ~WithFlexibleArray1() {} |
64 | int make_it_non_standard_layout; |
65 | private: |
66 | char private1[33]; |
67 | int flexible[]; // Don't insert padding after this field. |
68 | }; |
69 | |
70 | WithFlexibleArray1 with_flexible_array1; |
71 | // CHECK: %class.WithFlexibleArray1 = type { i32, [12 x i8], [33 x i8], [15 x i8], [0 x i32] } |
72 | |
73 | class WithFlexibleArray2 { |
74 | public: |
75 | char x[21]; |
76 | WithFlexibleArray1 flex1; // Don't insert padding after this field. |
77 | }; |
78 | |
79 | WithFlexibleArray2 with_flexible_array2; |
80 | // CHECK: %class.WithFlexibleArray2 = type { [21 x i8], [11 x i8], %class.WithFlexibleArray1 } |
81 | |
82 | class WithFlexibleArray3 { |
83 | public: |
84 | char x[13]; |
85 | WithFlexibleArray2 flex2; // Don't insert padding after this field. |
86 | }; |
87 | |
88 | WithFlexibleArray3 with_flexible_array3; |
89 | |
90 | |
91 | class Negative1 { |
92 | public: |
93 | Negative1() {} |
94 | int public1, public2; |
95 | }; |
96 | Negative1 negative1; |
97 | // CHECK: type { i32, i32 } |
98 | |
99 | class Negative2 { |
100 | public: |
101 | Negative2() {} |
102 | private: |
103 | int private1, private2; |
104 | }; |
105 | Negative2 negative2; |
106 | // CHECK: type { i32, i32 } |
107 | |
108 | union Negative3 { |
109 | char m1[8]; |
110 | long long m2; |
111 | }; |
112 | |
113 | Negative3 negative3; |
114 | // CHECK: type { i64 } |
115 | |
116 | class Negative4 { |
117 | public: |
118 | Negative4() {} |
119 | // No DTOR |
120 | int make_it_non_standard_layout; |
121 | private: |
122 | char private1; |
123 | int private2; |
124 | }; |
125 | |
126 | Negative4 negative4; |
127 | // CHECK: type { i32, i8, i32 } |
128 | |
129 | class __attribute__((packed)) Negative5 { |
130 | public: |
131 | Negative5() {} |
132 | ~Negative5() {} |
133 | int make_it_non_standard_layout; |
134 | private: |
135 | char private1; |
136 | int private2; |
137 | }; |
138 | |
139 | Negative5 negative5; |
140 | // CHECK: type <{ i32, i8, i32 }> |
141 | |
142 | |
143 | namespace SomeNamespace { |
144 | class BlacklistedByName { |
145 | public: |
146 | BlacklistedByName() {} |
147 | ~BlacklistedByName() {} |
148 | int make_it_non_standard_layout; |
149 | private: |
150 | char private1; |
151 | int private2; |
152 | }; |
153 | } // SomeNamespace |
154 | |
155 | SomeNamespace::BlacklistedByName blacklisted_by_name; |
156 | |
157 | extern "C" { |
158 | class ExternCStruct { |
159 | public: |
160 | ExternCStruct() {} |
161 | ~ExternCStruct() {} |
162 | int make_it_non_standard_layout; |
163 | private: |
164 | char private1; |
165 | int private2; |
166 | }; |
167 | } // extern "C" |
168 | |
169 | ExternCStruct extern_C_struct; |
170 | |
171 | // CTOR |
172 | // CHECK-LABEL: define {{.*}}Positive1C1Ev |
173 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}}12) |
174 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}}15) |
175 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}}12) |
176 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}}12) |
177 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}}8) |
178 | // CHECK-NOT: __asan_poison_intra_object_redzone |
179 | // CHECK: ret void |
180 | // |
181 | // DTOR |
182 | // CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}12) |
183 | // CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}15) |
184 | // CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}12) |
185 | // CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}12) |
186 | // CHECK: call void @__asan_unpoison_intra_object_redzone({{.*}}8) |
187 | // CHECK-NOT: __asan_unpoison_intra_object_redzone |
188 | // CHECK: ret void |
189 | // |
190 | // |
191 | // CHECK-LABEL: define linkonce_odr void @_ZN20ClassWithVirtualBaseC1Ev |
192 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}} 12) |
193 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}} 9) |
194 | // CHECK: call void @__asan_poison_intra_object_redzone({{.*}} 15) |
195 | // CHECK-NOT: __asan_poison_intra_object_redzone |
196 | // CHECK: ret void |
197 | // |
198 | |
199 | struct WithVirtualDtor { |
200 | virtual ~WithVirtualDtor(); |
201 | int x, y; |
202 | }; |
203 | struct InheritsFrom_WithVirtualDtor: WithVirtualDtor { |
204 | int a, b; |
205 | InheritsFrom_WithVirtualDtor() {} |
206 | ~InheritsFrom_WithVirtualDtor() {} |
207 | }; |
208 | |
209 | void Create_InheritsFrom_WithVirtualDtor() { |
210 | InheritsFrom_WithVirtualDtor x; |
211 | } |
212 | |
213 | |
214 | // Make sure the dtor of InheritsFrom_WithVirtualDtor remains in the code, |
215 | // i.e. we ignore -mconstructor-aliases when field paddings are added |
216 | // because the paddings in InheritsFrom_WithVirtualDtor needs to be unpoisoned |
217 | // in the dtor. |
218 | // WITH_CTOR_ALIASES-LABEL: define void @_Z35Create_InheritsFrom_WithVirtualDtor |
219 | // WITH_CTOR_ALIASES-NOT: call void @_ZN15WithVirtualDtorD2Ev |
220 | // WITH_CTOR_ALIASES: call void @_ZN28InheritsFrom_WithVirtualDtorD2Ev |
221 | // WITH_CTOR_ALIASES: ret void |
222 | |
223 | // Make sure we don't emit memcpy for operator= if paddings are inserted. |
224 | struct ClassWithTrivialCopy { |
225 | ClassWithTrivialCopy(); |
226 | ~ClassWithTrivialCopy(); |
227 | void *a; |
228 | private: |
229 | void *c; |
230 | }; |
231 | |
232 | void MakeTrivialCopy(ClassWithTrivialCopy *s1, ClassWithTrivialCopy *s2) { |
233 | *s1 = *s2; |
234 | ClassWithTrivialCopy s3(*s2); |
235 | } |
236 | |
237 | // CHECK-LABEL: define void @_Z15MakeTrivialCopyP20ClassWithTrivialCopyS0_ |
238 | // CHECK-NOT: memcpy |
239 | // CHECK: ret void |
240 | |