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