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