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