// 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 -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