// Test -fsanitize-address-field-padding
// RUN: echo 'type:SomeNamespace::IgnorelistedByName=field-padding' > %t.type.ignorelist
// RUN: echo 'src:*sanitize-address-field-padding.cpp=field-padding' > %t.file.ignorelist
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsanitize=address -fsanitize-address-field-padding=1 -fsanitize-ignorelist=%t.type.ignorelist -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-ignorelist=%t.type.ignorelist -Rsanitize-address -emit-llvm -o - %s -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-ignorelist=%t.file.ignorelist -Rsanitize-address -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=FILE_IGNORELIST
// 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::IgnorelistedByName because it is ignorelisted
// CHECK: -fsanitize-address-field-padding ignored for ExternCStruct because it is not C++
//
// FILE_IGNORELIST: -fsanitize-address-field-padding ignored for Positive1 because it is in a ignorelisted file
// FILE_IGNORELIST-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 IgnorelistedByName {
public:
IgnorelistedByName() {}
~IgnorelistedByName() {}
int make_it_non_standard_layout;
private:
char private1;
int private2;
};
} // SomeNamespace
SomeNamespace::IgnorelistedByName ignorelisted_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