diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1649,23 +1649,35 @@ } }; - static void EmitSanitizerDtorCallback(CodeGenFunction &CGF, llvm::Value *Ptr, - CharUnits::QuantityType PoisonSize) { + static void EmitSanitizerDtorCallback( + CodeGenFunction &CGF, StringRef Name, llvm::Value *Ptr, + llvm::Optional PoisonSize = {}) { CodeGenFunction::SanitizerScope SanScope(&CGF); // Pass in void pointer and size of region as arguments to runtime // function - llvm::Value *Args[] = {CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy), - llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)}; + SmallVector Args = { + CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy)}; + SmallVector ArgTypes = {CGF.VoidPtrTy}; - llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy}; + if (PoisonSize.has_value()) { + Args.emplace_back(llvm::ConstantInt::get(CGF.SizeTy, *PoisonSize)); + ArgTypes.emplace_back(CGF.SizeTy); + } llvm::FunctionType *FnType = llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false); - llvm::FunctionCallee Fn = - CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback"); + llvm::FunctionCallee Fn = CGF.CGM.CreateRuntimeFunction(FnType, Name); + CGF.EmitNounwindRuntimeCall(Fn, Args); } + static void + EmitSanitizerDtorFieldsCallback(CodeGenFunction &CGF, llvm::Value *Ptr, + CharUnits::QuantityType PoisonSize) { + EmitSanitizerDtorCallback(CGF, "__sanitizer_dtor_callback_fields", Ptr, + PoisonSize); + } + /// Poison base class with a trivial destructor. struct SanitizeDtorTrivialBase final : EHScopeStack::Cleanup { const CXXRecordDecl *BaseClass; @@ -1687,7 +1699,8 @@ if (!BaseSize.isPositive()) return; - EmitSanitizerDtorCallback(CGF, Addr.getPointer(), BaseSize.getQuantity()); + EmitSanitizerDtorFieldsCallback(CGF, Addr.getPointer(), + BaseSize.getQuantity()); // Prevent the current stack frame from disappearing from the stack trace. CGF.CurFn->addFnAttr("disable-tail-calls", "true"); @@ -1735,7 +1748,7 @@ if (!PoisonSize.isPositive()) return; - EmitSanitizerDtorCallback(CGF, OffsetPtr, PoisonSize.getQuantity()); + EmitSanitizerDtorFieldsCallback(CGF, OffsetPtr, PoisonSize.getQuantity()); // Prevent the current stack frame from disappearing from the stack trace. CGF.CurFn->addFnAttr("disable-tail-calls", "true"); @@ -1752,15 +1765,13 @@ void Emit(CodeGenFunction &CGF, Flags flags) override { assert(Dtor->getParent()->isDynamicClass()); (void)Dtor; - ASTContext &Context = CGF.getContext(); // Poison vtable and vtable ptr if they exist for this class. llvm::Value *VTablePtr = CGF.LoadCXXThis(); - CharUnits::QuantityType PoisonSize = - Context.toCharUnitsFromBits(CGF.PointerWidthInBits).getQuantity(); // Pass in void pointer and size of region as arguments to runtime // function - EmitSanitizerDtorCallback(CGF, VTablePtr, PoisonSize); + EmitSanitizerDtorCallback(CGF, "__sanitizer_dtor_callback_vptr", + VTablePtr); } }; diff --git a/clang/test/CodeGenCXX/sanitize-dtor-bit-field.cpp b/clang/test/CodeGenCXX/sanitize-dtor-bit-field.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-bit-field.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-bit-field.cpp @@ -63,22 +63,22 @@ Adjacent ad; // CHECK-LABEL: define {{.*}}PackedD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}i64 17{{.*}}, !dbg ![[DI1:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}i64 17{{.*}}, !dbg ![[DI1:[0-9]+]] // CHECK: ret void // CHECK-LABEL: define {{.*}}EmptyD2Ev // CHECK: ret void // CHECK-LABEL: define {{.*}}SimpleD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}i64 1{{.*}}, !dbg ![[DI2:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}i64 1{{.*}}, !dbg ![[DI2:[0-9]+]] // CHECK: ret void // CHECK-LABEL: define {{.*}}AnonD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}i64 5{{.*}}, !dbg ![[DI3:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}i64 5{{.*}}, !dbg ![[DI3:[0-9]+]] // CHECK: ret void // CHECK-LABEL: define {{.*}}AdjacentD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}i64 1{{.*}}, !dbg ![[DI4:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}i64 1{{.*}}, !dbg ![[DI4:[0-9]+]] // CHECK: ret void // CHECK-LABEL: !DIFile{{.*}}cpp diff --git a/clang/test/CodeGenCXX/sanitize-dtor-callback.cpp b/clang/test/CodeGenCXX/sanitize-dtor-callback.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-callback.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-callback.cpp @@ -56,16 +56,16 @@ // instrumentation inserted. // CHECK-LABEL: define {{.*}}SimpleD2Ev // CHECK-NOT: store i{{[0-9]+}} 0, {{.*}}@__msan_param_tls -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI1:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, !dbg ![[DI1:[0-9]+]] // CHECK: ret void // CHECK-LABEL: define {{.*}}InlinedD2Ev // CHECK-NOT: store i{{[0-9]+}} 0, {{.*}}@__msan_param_tls -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI2:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, !dbg ![[DI2:[0-9]+]] // CHECK: ret void // CHECK-LABEL: define {{.*}}Defaulted_Non_TrivialD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI3:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, !dbg ![[DI3:[0-9]+]] // CHECK: ret void // CHECK-LABEL: !DIFile{{.*}}cpp diff --git a/clang/test/CodeGenCXX/sanitize-dtor-derived-class.cpp b/clang/test/CodeGenCXX/sanitize-dtor-derived-class.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-derived-class.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-derived-class.cpp @@ -49,15 +49,15 @@ // Poison members and vtable ptr. // CHECK-LABEL: define {{.*}}BaseD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI1:[0-9]+]] -// CHECK: call void @__sanitizer_dtor_callback({{.*}}i64 8{{.*}}, !dbg ![[DI1]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, !dbg ![[DI1:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_vptr({{.*}}){{.*}}, !dbg ![[DI1]] // CHECK: ret void // Poison members and destroy non-virtual base. // CHECK-LABEL: define {{.*}}DerivedD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI3:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, !dbg ![[DI3:[0-9]+]] // CHECK: call void {{.*}}BaseD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}i64 8{{.*}}, !dbg ![[DI3]] +// CHECK: call void @__sanitizer_dtor_callback_vptr({{.*}}){{.*}}, !dbg ![[DI3]] // CHECK: ret void // CHECK-LABEL: !DIFile{{.*}}cpp diff --git a/clang/test/CodeGenCXX/sanitize-dtor-nontrivial-virtual-base.cpp b/clang/test/CodeGenCXX/sanitize-dtor-nontrivial-virtual-base.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-nontrivial-virtual-base.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-nontrivial-virtual-base.cpp @@ -47,7 +47,7 @@ // CHECK-LABEL: define {{.*}}ZN7DerivedD1Ev // CHECK: call void {{.*}}ZN11VirtualBaseD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}){{.*}}, !dbg ![[DI0:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_vptr({{.*}}){{.*}}, !dbg ![[DI0:[0-9]+]] // CHECK: ret void // CHECK-LABEL: define {{.*}}ZN7DerivedD0Ev @@ -61,27 +61,27 @@ // poison 2 ints // CHECK-LABEL: define {{.*}}ZN11VirtualBaseD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, i64 8){{.*}}, !dbg ![[DI1:[0-9]+]] -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, i64 8){{.*}}, !dbg ![[DI1:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_vptr({{.*}}){{.*}}, !dbg ![[DI1]] // CHECK: ret void // poison int and double // CHECK-LABEL: define {{.*}}ZN4BaseD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}{{.*}}, !dbg ![[DI2:[0-9]+]] -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, i64 16){{.*}}, !dbg ![[DI2:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_vptr({{.*}}{{.*}}, !dbg ![[DI2]] // CHECK: ret void // poison int, ignore vector, poison int // CHECK-LABEL: define {{.*}}ZN7DerivedD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, i64 4){{.*}}, !dbg ![[DI3:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, i64 4){{.*}}, !dbg ![[DI3:[0-9]+]] // CHECK: call void {{.*}}ZN6VectorIiED1Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, i64 4){{.*}}, !dbg ![[DI3]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, i64 4){{.*}}, !dbg ![[DI3]] // CHECK: call void {{.*}}ZN4BaseD2Ev // CHECK: ret void // poison int // CHECK-LABEL: define {{.*}}ZN6VectorIiED2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, i64 4){{.*}}, !dbg ![[DI5:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, i64 4){{.*}}, !dbg ![[DI5:[0-9]+]] // CHECK: ret void // CHECK-LABEL: !DIFile{{.*}}.cpp diff --git a/clang/test/CodeGenCXX/sanitize-dtor-tail-call.cpp b/clang/test/CodeGenCXX/sanitize-dtor-tail-call.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-tail-call.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-tail-call.cpp @@ -15,7 +15,7 @@ Simple s; // Simple internal member is poisoned by compiler-generated dtor // CHECK: define {{.*}}SimpleD2Ev{{.*}} [[ATTRIBUTE:#[0-9]+]] -// CHECK: {{^ *}}call void @__sanitizer_dtor_callback( +// CHECK: call void @__sanitizer_dtor_callback_fields( // CHECK: ret void // Destructor does not emit any tail calls diff --git a/clang/test/CodeGenCXX/sanitize-dtor-trivial-base.cpp b/clang/test/CodeGenCXX/sanitize-dtor-trivial-base.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-trivial-base.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-trivial-base.cpp @@ -20,8 +20,8 @@ // Poison members, then poison the trivial base class. // CHECK-LABEL: define {{.*}}DerivedD2Ev // CHECK: %[[GEP:[0-9a-z]+]] = getelementptr i8, i8* {{.*}}, i64 16 -// CHECK: call void @__sanitizer_dtor_callback({{.*}}%[[GEP]], i64 4{{.*}}, !dbg ![[DI:[0-9]+]] -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, i64 16{{.*}}, !dbg ![[DI]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}%[[GEP]], i64 4{{.*}}, !dbg ![[DI:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, i64 16{{.*}}, !dbg ![[DI]] // CHECK: ret void // CHECK-LABEL: !DIFile{{.*}}cpp diff --git a/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp b/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp @@ -25,18 +25,18 @@ // CHECK-LABEL: define {{.*}}BD1Ev // CHECK: call void {{.*}}BD2Ev // CHECK: call void {{.*}}AD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI1:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_vptr({{.*}}, !dbg ![[DI1:[0-9]+]] // CHECK: ret void // Since no virtual bases, poison vtable ptr here. // CHECK-LABEL: define {{.*}}AD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI2:[0-9]+]] -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI2]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, !dbg ![[DI2:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_vptr({{.*}}, !dbg ![[DI2]] // CHECK: ret void // Poison members // CHECK-LABEL: define {{.*}}BD2Ev -// CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI4:[0-9]+]] +// CHECK: call void @__sanitizer_dtor_callback_fields({{.*}}, !dbg ![[DI4:[0-9]+]] // CHECK: ret void // CHECK-LABEL: !DIFile{{.*}}cpp diff --git a/clang/test/CodeGenCXX/sanitize-dtor-zero-size-field.cpp b/clang/test/CodeGenCXX/sanitize-dtor-zero-size-field.cpp --- a/clang/test/CodeGenCXX/sanitize-dtor-zero-size-field.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-zero-size-field.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -no-opaque-pointers -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-passes -std=c++20 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s --implicit-check-not "call void @__sanitizer_dtor_callback" -// RUN: %clang_cc1 -no-opaque-pointers -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-passes -std=c++20 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s --implicit-check-not "call void @__sanitizer_dtor_callback" +// RUN: %clang_cc1 -no-opaque-pointers -O0 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-passes -std=c++20 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s --implicit-check-not "call void @__sanitizer_dtor_callback_fields" +// RUN: %clang_cc1 -no-opaque-pointers -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-passes -std=c++20 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s --implicit-check-not "call void @__sanitizer_dtor_callback_fields" struct Empty {}; @@ -30,7 +30,7 @@ static_assert(sizeof(Struct) == 16); } // namespace T0 // CHECK-LABEL: define {{.*}} @_ZN2T06StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 13) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 13) // CHECK-NEXT: ret void namespace empty { @@ -45,7 +45,7 @@ } // namespace T1 // CHECK-LABEL: define {{.*}} @_ZN5empty2T16StructD2Ev( // CHECK: [[GEP:%.+]] = getelementptr i8, {{.*}}, i64 8{{$}} -// CHECK: call void @__sanitizer_dtor_callback(i8* [[GEP]], i64 13) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* [[GEP]], i64 13) // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK-NEXT: ret void @@ -60,10 +60,10 @@ } // namespace T2 // CHECK-LABEL: define {{.*}} @_ZN5empty2T26StructD2Ev( // CHECK: [[GEP1:%.+]] = getelementptr i8, {{.*}}, i64 16{{$}} -// CHECK: call void @__sanitizer_dtor_callback(i8* [[GEP1]], i64 5) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* [[GEP1]], i64 5) // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK: [[GEP2:%.+]] = getelementptr i8, {{.*}}, i64 0{{$}} -// CHECK: call void @__sanitizer_dtor_callback(i8* [[GEP2]], i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* [[GEP2]], i64 8) // CHECK-NEXT: ret void namespace T3 { @@ -77,10 +77,10 @@ } // namespace T3 // CHECK-LABEL: define {{.*}} @_ZN5empty2T36StructD2Ev( // CHECK: [[GEP1:%.+]] = getelementptr i8, {{.*}}, i64 20{{$}} -// CHECK: call void @__sanitizer_dtor_callback(i8* [[GEP1]], i64 1) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* [[GEP1]], i64 1) // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK: [[GEP2:%.+]] = getelementptr i8, {{.*}}, i64 0{{$}} -// CHECK: call void @__sanitizer_dtor_callback(i8* [[GEP2]], i64 12) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* [[GEP2]], i64 12) // CHECK-NEXT: ret void namespace T4 { @@ -93,7 +93,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T4 // CHECK-LABEL: define {{.*}} @_ZN5empty2T46StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 16) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 16) // CHECK-NEXT: ret void namespace T5 { @@ -107,7 +107,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T5 // CHECK-LABEL: define {{.*}} @_ZN5empty2T56StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 13) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 13) // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK-NEXT: ret void @@ -122,7 +122,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T6 // CHECK-LABEL: define {{.*}} @_ZN5empty2T66StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 13) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 13) // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK-NEXT: ret void @@ -137,9 +137,9 @@ static_assert(sizeof(Struct) == 24); } // namespace T7 // CHECK-LABEL: define {{.*}} @_ZN5empty2T76StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 5) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 5) // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 8) // CHECK-NEXT: ret void namespace T8 { @@ -153,8 +153,8 @@ static_assert(sizeof(Struct) == 24); } // namespace T8 // CHECK-LABEL: define {{.*}} @_ZN5empty2T86StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 5) -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 5) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 8) // CHECK-NEXT: ret void namespace T9 { @@ -168,8 +168,8 @@ static_assert(sizeof(Struct) == 24); } // namespace T9 // CHECK-LABEL: define {{.*}} @_ZN5empty2T96StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 1) -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 12) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 1) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 12) // CHECK-NEXT: ret void namespace T10 { @@ -183,8 +183,8 @@ static_assert(sizeof(Struct) == 24); } // namespace T10 // CHECK-LABEL: define {{.*}} @_ZN5empty3T106StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 1) -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 12) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 1) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 12) // CHECK-NEXT: ret void namespace T11 { @@ -198,7 +198,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T11 // CHECK-LABEL: define {{.*}} @_ZN5empty3T116StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 16) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 16) // CHECK-NEXT: ret void namespace T12 { @@ -214,7 +214,7 @@ } // namespace empty // CHECK-LABEL: define {{.*}} @_ZN5empty3T126StructD2Ev( // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 16) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 16) // CHECK-NEXT: ret void namespace empty_non_trivial { @@ -228,7 +228,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T1 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T16StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 13) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 13) // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK-NEXT: ret void @@ -242,8 +242,8 @@ static_assert(sizeof(Struct) == 24); } // namespace T2 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T26StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 5) -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 5) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 8) // CHECK-NEXT: ret void namespace T3 { @@ -256,8 +256,8 @@ static_assert(sizeof(Struct) == 24); } // namespace T3 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T36StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 1) -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 12) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 1) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 12) // CHECK-NEXT: ret void namespace T4 { @@ -270,7 +270,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T4 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T46StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 16) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 16) // CHECK-NEXT: ret void namespace T5 { @@ -284,7 +284,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T5 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T56StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 13) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 13) // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK-NEXT: ret void @@ -300,7 +300,7 @@ static_assert(sizeof(Struct) == 24); } // namespace T6 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T66StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 13) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 13) // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK: call void @_ZN10NonTrivialD1Ev( // CHECK-NEXT: ret void @@ -316,10 +316,10 @@ static_assert(sizeof(Struct) == 24); } // namespace T7 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T76StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 5) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 5) // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 8) // CHECK-NEXT: ret void namespace T8 { @@ -333,9 +333,9 @@ static_assert(sizeof(Struct) == 24); } // namespace T8 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T86StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 5) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 5) // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 8) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 8) // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK-NEXT: ret void @@ -350,10 +350,10 @@ static_assert(sizeof(Struct) == 24); } // namespace T9 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial2T96StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 1) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 1) // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 12) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 12) // CHECK-NEXT: ret void namespace T10 { @@ -367,9 +367,9 @@ static_assert(sizeof(Struct) == 24); } // namespace T10 // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial3T106StructD2Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 1) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 1) // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 12) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 12) // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK-NEXT: ret void @@ -386,7 +386,7 @@ // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial3T116StructD2Ev( // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 16) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 16) // CHECK-NEXT: ret void namespace T12 { @@ -402,6 +402,6 @@ } // namespace empty_non_trivial // CHECK-LABEL: define {{.*}} @_ZN17empty_non_trivial3T126StructD2Ev( // CHECK: call void @_ZN10NonTrivialD1Ev( -// CHECK: call void @__sanitizer_dtor_callback(i8* {{.*}}, i64 16) +// CHECK: call void @__sanitizer_dtor_callback_fields(i8* {{.*}}, i64 16) // CHECK: call void @_ZN15EmptyNonTrivialD1Ev( // CHECK: ret void diff --git a/compiler-rt/include/sanitizer/msan_interface.h b/compiler-rt/include/sanitizer/msan_interface.h --- a/compiler-rt/include/sanitizer/msan_interface.h +++ b/compiler-rt/include/sanitizer/msan_interface.h @@ -92,6 +92,8 @@ /* Tell MSan about newly destroyed memory. Mark memory as uninitialized. */ void __sanitizer_dtor_callback(const volatile void* data, size_t size); + void __sanitizer_dtor_callback_fields(const volatile void *data, size_t size); + void __sanitizer_dtor_callback_vptr(const volatile void *data); /* This function may be optionally provided by user and should return a string containing Msan runtime options. See msan_flags.h for details. */ diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -349,6 +349,8 @@ u32 ChainOrigin(u32 id, StackTrace *stack); const int STACK_TRACE_TAG_POISON = StackTrace::TAG_CUSTOM + 1; +const int STACK_TRACE_TAG_FIELDS = STACK_TRACE_TAG_POISON + 1; +const int STACK_TRACE_TAG_VPTR = STACK_TRACE_TAG_FIELDS + 1; #define GET_MALLOC_STACK_TRACE \ BufferedStackTrace stack; \ diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -944,6 +944,22 @@ } } +void __sanitizer_dtor_callback_fields(const void *data, uptr size) { + if (flags()->poison_in_dtor) { + GET_MALLOC_STACK_TRACE; + stack.tag = STACK_TRACE_TAG_FIELDS; + PoisonMemory(data, size, &stack); + } +} + +void __sanitizer_dtor_callback_vptr(const void *data) { + if (flags()->poison_in_dtor) { + GET_MALLOC_STACK_TRACE; + stack.tag = STACK_TRACE_TAG_VPTR; + PoisonMemory(data, sizeof(void *), &stack); + } +} + template static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF64_T offset) { diff --git a/compiler-rt/lib/msan/msan_interface_internal.h b/compiler-rt/lib/msan/msan_interface_internal.h --- a/compiler-rt/lib/msan/msan_interface_internal.h +++ b/compiler-rt/lib/msan/msan_interface_internal.h @@ -162,6 +162,10 @@ // uninitialized. SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dtor_callback(const void* data, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_dtor_callback_fields(const void *data, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_dtor_callback_vptr(const void *data); SANITIZER_INTERFACE_ATTRIBUTE u16 __sanitizer_unaligned_load16(const uu16 *p); diff --git a/compiler-rt/lib/msan/msan_report.cpp b/compiler-rt/lib/msan/msan_report.cpp --- a/compiler-rt/lib/msan/msan_report.cpp +++ b/compiler-rt/lib/msan/msan_report.cpp @@ -81,6 +81,13 @@ Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(), d.Default()); break; + case STACK_TRACE_TAG_FIELDS: + Printf(" %sMember fields were destroyed%s\n", d.Origin(), d.Default()); + break; + case STACK_TRACE_TAG_VPTR: + Printf(" %sVirtual table ptr was destroyed%s\n", d.Origin(), + d.Default()); + break; default: Printf(" %sUninitialized value was created%s\n", d.Origin(), d.Default()); diff --git a/compiler-rt/test/msan/dtor-base-access.cpp b/compiler-rt/test/msan/dtor-base-access.cpp --- a/compiler-rt/test/msan/dtor-base-access.cpp +++ b/compiler-rt/test/msan/dtor-base-access.cpp @@ -66,17 +66,17 @@ assert(__msan_test_shadow(&g->d, sizeof(g->d)) == 0); __msan_print_shadow(&g->tb0, sizeof(g->tb0)); - // CHECK: Memory was marked as uninitialized + // CHECK: Member fields were destroyed // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} // CHECK: {{#1 0x.* in .*~Derived.*cpp:}}[[@LINE-20]]: __msan_print_shadow(&g->b, sizeof(g->b)); - // CHECK: Memory was marked as uninitialized + // CHECK: Member fields were destroyed // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} // CHECK: {{#1 0x.* in .*~Base.*cpp:}}[[@LINE-33]]: __msan_print_shadow(&g->tb1, sizeof(g->tb1)); - // CHECK: Memory was marked as uninitialized + // CHECK: Member fields were destroyed // CHECK: {{#0 0x.* in __sanitizer_dtor_callback}} // CHECK: {{#1 0x.* in .*~Derived.*cpp:}}[[@LINE-30]]: diff --git a/compiler-rt/test/msan/dtor-vtable-multiple-inheritance.cpp b/compiler-rt/test/msan/dtor-vtable-multiple-inheritance.cpp --- a/compiler-rt/test/msan/dtor-vtable-multiple-inheritance.cpp +++ b/compiler-rt/test/msan/dtor-vtable-multiple-inheritance.cpp @@ -51,8 +51,8 @@ // This fails #ifdef CVPTR c->A_Foo(); -// CVPTR: Memory was marked as uninitialized -// CVPTR: {{#0 0x.* in __sanitizer_dtor_callback}} +// CVPTR: Virtual table ptr was destroyed +// CVPTR: {{#0 0x.* in __sanitizer_dtor_callback_vptr}} // CVPTR: {{#1 0x.* in ~C .*cpp:}}[[@LINE-28]]: // CVPTR: {{#2 0x.* in main .*cpp:}}[[@LINE-7]]: #endif @@ -63,16 +63,16 @@ // Both of these fail #ifdef EAVPTR e->A_Foo(); -// EAVPTR: Memory was marked as uninitialized -// EAVPTR: {{#0 0x.* in __sanitizer_dtor_callback}} +// EAVPTR: Virtual table ptr was destroyed +// EAVPTR: {{#0 0x.* in __sanitizer_dtor_callback_vptr}} // EAVPTR: {{#1 0x.* in ~E .*cpp:}}[[@LINE-25]]: // EAVPTR: {{#2 0x.* in main .*cpp:}}[[@LINE-7]]: #endif #ifdef EDVPTR e->D_Foo(); -// EDVPTR: Memory was marked as uninitialized -// EDVPTR: {{#0 0x.* in __sanitizer_dtor_callback}} +// EDVPTR: Virtual table ptr was destroyed +// EDVPTR: {{#0 0x.* in __sanitizer_dtor_callback_vptr}} // EDVPTR: {{#1 0x.* in ~E .*cpp:}}[[@LINE-33]]: // EDVPTR: {{#2 0x.* in main .*cpp:}}[[@LINE-15]]: #endif diff --git a/compiler-rt/test/msan/use-after-dtor.cpp b/compiler-rt/test/msan/use-after-dtor.cpp --- a/compiler-rt/test/msan/use-after-dtor.cpp +++ b/compiler-rt/test/msan/use-after-dtor.cpp @@ -32,7 +32,7 @@ // CHECK-UAD: WARNING: MemorySanitizer: use-of-uninitialized-value // CHECK-UAD: {{#0 0x.* in main.*use-after-dtor.cpp:}}[[@LINE-3]] - // CHECK-ORIGINS: Memory was marked as uninitialized + // CHECK-ORIGINS: Member fields were destroyed // CHECK-ORIGINS: {{#0 0x.* in __sanitizer_dtor_callback}} // CHECK-ORIGINS: {{#1 0x.* in .*~Simple.*cpp:}}[[@LINE-18]]: