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:
Positive1()30   Positive1() {}
~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:
ClassWithVirtualBase()50   ClassWithVirtualBase() {}
~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:
WithFlexibleArray1()62   WithFlexibleArray1() {}
~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:
Negative1()93   Negative1() {}
94   int public1, public2;
95 };
96 Negative1 negative1;
97 // CHECK: type { i32, i32 }
98 
99 class Negative2 {
100  public:
Negative2()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:
Negative4()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:
Negative5()131   Negative5() {}
~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:
BlacklistedByName()146   BlacklistedByName() {}
~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:
ExternCStruct()160   ExternCStruct() {}
~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;
InheritsFrom_WithVirtualDtorInheritsFrom_WithVirtualDtor205   InheritsFrom_WithVirtualDtor() {}
~InheritsFrom_WithVirtualDtorInheritsFrom_WithVirtualDtor206   ~InheritsFrom_WithVirtualDtor() {}
207 };
208 
Create_InheritsFrom_WithVirtualDtor()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 
MakeTrivialCopy(ClassWithTrivialCopy * s1,ClassWithTrivialCopy * s2)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