From c059ede28ea8faf0540cedad74bc5698ec59e744 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 29 Aug 2022 20:33:01 -0700 Subject: [PATCH] [msan] Add more specific messages for use-after-destroy Reviewed By: kda, kstoimenov Differential Revision: https://reviews.llvm.org/D132907 --- clang/lib/CodeGen/CGClass.cpp | 37 ++++++---- clang/test/CodeGenCXX/sanitize-dtor-bit-field.cpp | 8 +-- clang/test/CodeGenCXX/sanitize-dtor-callback.cpp | 6 +- .../CodeGenCXX/sanitize-dtor-derived-class.cpp | 8 +-- .../sanitize-dtor-nontrivial-virtual-base.cpp | 16 ++--- clang/test/CodeGenCXX/sanitize-dtor-tail-call.cpp | 2 +- .../test/CodeGenCXX/sanitize-dtor-trivial-base.cpp | 4 +- clang/test/CodeGenCXX/sanitize-dtor-trivial.cpp | 5 +- clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp | 8 +-- .../CodeGenCXX/sanitize-dtor-zero-size-field.cpp | 78 +++++++++++----------- compiler-rt/include/sanitizer/msan_interface.h | 2 + compiler-rt/lib/msan/msan.h | 2 + compiler-rt/lib/msan/msan_interceptors.cpp | 16 +++++ compiler-rt/lib/msan/msan_interface_internal.h | 4 ++ compiler-rt/lib/msan/msan_report.cpp | 7 ++ compiler-rt/test/msan/dtor-base-access.cpp | 6 +- .../test/msan/dtor-vtable-multiple-inheritance.cpp | 12 ++-- compiler-rt/test/msan/use-after-dtor.cpp | 2 +- 18 files changed, 132 insertions(+), 91 deletions(-) diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 703eff8..ec4d8e5 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1649,23 +1649,35 @@ namespace { } }; - 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 @@ namespace { 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 @@ namespace { 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 @@ namespace { 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 index 6629cd8..94571d4 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-bit-field.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-bit-field.cpp @@ -63,22 +63,22 @@ struct Adjacent { 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 index d42008a..18c6417 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-callback.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-callback.cpp @@ -56,16 +56,16 @@ Defaulted_Non_Trivial def_non_trivial; // 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 index 1a6aa9e..1d5accb 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-derived-class.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-derived-class.cpp @@ -49,15 +49,15 @@ Derived d; // 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 index d30bd3a..adbe77f 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-nontrivial-virtual-base.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-nontrivial-virtual-base.cpp @@ -47,7 +47,7 @@ Derived d; // 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 @@ Derived d; // 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 index 3d52e72..5cdf69e 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-tail-call.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-tail-call.cpp @@ -15,7 +15,7 @@ struct Simple { 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 index 5da9405..cfb80f8 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-trivial-base.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-trivial-base.cpp @@ -20,8 +20,8 @@ Derived d; // 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-trivial.cpp b/clang/test/CodeGenCXX/sanitize-dtor-trivial.cpp index eb60f7f..e2b1942 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-trivial.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-trivial.cpp @@ -14,7 +14,6 @@ Trivial t; // CHECK: call void @__sanitizer_dtor_callback({{.*}}, !dbg ![[DI:[0-9]+]] +// CHECK-LABEL: !DIFile{{.*}}.cpp -// CHECK-LABEL: !DIFile{{.*}}cpp - -// CHECK-DAG: ![[DI]] = {{.*}}line: [[@LINE-28]] +// CHECK-DAG: ![[DI]] = {{.*}}line: [[@LINE-371]] diff --git a/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp b/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp index 063ff7f..49de930 100644 --- a/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp +++ b/clang/test/CodeGenCXX/sanitize-dtor-vtable.cpp @@ -25,18 +25,18 @@ B b; // 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 index a0b0631..7aba27e 100644 --- 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 @@ struct Struct { 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 @@ static_assert(sizeof(Struct) == 24); } // 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 @@ static_assert(sizeof(Struct) == 24); } // 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 @@ static_assert(sizeof(Struct) == 24); } // 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ static_assert(sizeof(Struct) == 24); } // 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ struct Struct { 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 @@ static_assert(sizeof(Struct) == 24); // 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 @@ static_assert(sizeof(Struct) == 24); } // 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 index eeb39fb..854b12c 100644 --- a/compiler-rt/include/sanitizer/msan_interface.h +++ b/compiler-rt/include/sanitizer/msan_interface.h @@ -92,6 +92,8 @@ extern "C" { /* 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 index 1a4cc8c..5dc57fd 100644 --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -349,6 +349,8 @@ void UnpoisonThreadLocalState(); 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 index c4a9e88..b3d5484 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -944,6 +944,22 @@ void __sanitizer_dtor_callback(const void *data, uptr size) { } } +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 index 535c3fc..c2eead1 100644 --- a/compiler-rt/lib/msan/msan_interface_internal.h +++ b/compiler-rt/lib/msan/msan_interface_internal.h @@ -162,6 +162,10 @@ void __msan_allocated_memory(const void* data, uptr size); // 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 index c8fc286..d1ef36d 100644 --- a/compiler-rt/lib/msan/msan_report.cpp +++ b/compiler-rt/lib/msan/msan_report.cpp @@ -81,6 +81,13 @@ static void DescribeOrigin(u32 id) { 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 index 1e141d5..e182af2 100644 --- a/compiler-rt/test/msan/dtor-base-access.cpp +++ b/compiler-rt/test/msan/dtor-base-access.cpp @@ -66,17 +66,17 @@ int main() { 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 index 7e50c49..600102c 100644 --- a/compiler-rt/test/msan/dtor-vtable-multiple-inheritance.cpp +++ b/compiler-rt/test/msan/dtor-vtable-multiple-inheritance.cpp @@ -51,8 +51,8 @@ int main() { // 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 @@ int main() { // 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 index 67582c1..385dc34 100644 --- a/compiler-rt/test/msan/use-after-dtor.cpp +++ b/compiler-rt/test/msan/use-after-dtor.cpp @@ -32,7 +32,7 @@ int main() { // 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]]: -- 2.7.4