Index: diff.patch =================================================================== --- /dev/null +++ diff.patch @@ -0,0 +1,58 @@ +diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp +index 740cd4a..292786e 100644 +--- a/lib/CodeGen/CGClass.cpp ++++ b/lib/CodeGen/CGClass.cpp +@@ -1376,9 +1376,31 @@ static void EmitDtorSanitizerCallback(CodeGenFunction &CGF, + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(Dtor->getParent()); + ++ ASTContext &Context = CGF.getContext(); ++ ++ CharUnits::QuantityType PoisonSize = Layout.getSize().getQuantity() - Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity(); ++ llvm::ConstantInt *TotalSize = llvm::ConstantInt::get(CGF.SizeTy, ++ Layout.getSize().getQuantity()); ++ llvm::ConstantInt *PoisonSizePtr = llvm::ConstantInt::get(CGF.SizeTy, PoisonSize); ++ llvm::ConstantInt *OffsetSizePtr = llvm::ConstantInt::get(CGF.SizeTy, Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity()); ++ ++ llvm::Value *ThisPtr = CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.Int8PtrTy); ++ llvm::Value *OffsetPtr = CGF.Builder.CreateGEP(ThisPtr, OffsetSizePtr); ++ ++ printf("this total size %lu \t members %u \t type id %d\n", *(TotalSize->getValue().getRawData()), ++ Layout.getFieldCount(), ThisPtr->getType()->getTypeID()); ++ printf(" off poison size %lu \t offset size %lu \t type id %d\n", *(PoisonSizePtr->getValue().getRawData()), ++ *(OffsetSizePtr->getValue().getRawData()), OffsetSizePtr->getType()->getTypeID()); ++ ++ llvm::Value *Args[] = { ++ CGF.Builder.CreateBitCast(OffsetPtr, CGF.VoidPtrTy), ++ llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)}; ++ ++ /* + llvm::Value *Args[] = { + CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.VoidPtrTy), + llvm::ConstantInt::get(CGF.SizeTy, Layout.getSize().getQuantity())}; ++ */ + llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy}; + + llvm::FunctionType *FnType = +@@ -1471,17 +1493,16 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { + break; + } + ++ // Insert memory-poisoning instrumentation. ++ if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor) ++ EmitDtorSanitizerCallback(*this, Dtor); ++ + // Jump out through the epilogue cleanups. + DtorEpilogue.ForceCleanup(); + + // Exit the try if applicable. + if (isTryBody) + ExitCXXTryStmt(*cast(Body), true); +- +- // Insert memory-poisoning instrumentation. +- if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor +- && SanOpts.has(SanitizerKind::Memory)) +- EmitDtorSanitizerCallback(*this, Dtor); + } + + void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) { Index: lib/CodeGen/CGClass.cpp =================================================================== --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -1376,9 +1376,29 @@ const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(Dtor->getParent()); + // Construct pointer to region to begin poisoning, and calculate poison + // size, so that only members declared in this class are poisoned. + llvm::Value *OffsetPtr; + CharUnits::QuantityType PoisonSize; + if(Layout.getFieldCount() > 0) { + ASTContext &Context = CGF.getContext(); + llvm::ConstantInt *OffsetSizePtr = llvm::ConstantInt::get(CGF.SizeTy, + Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity()); + + OffsetPtr = CGF.Builder.CreateGEP(CGF.Builder. + CreateBitCast(CGF.LoadCXXThis(), CGF.Int8PtrTy), OffsetSizePtr); + + PoisonSize = Layout.getSize().getQuantity() - + Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity(); + } else { + OffsetPtr = CGF.LoadCXXThis(); + PoisonSize = Layout.getSize().getQuantity(); + } + llvm::Value *Args[] = { - CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.VoidPtrTy), - llvm::ConstantInt::get(CGF.SizeTy, Layout.getSize().getQuantity())}; + CGF.Builder.CreateBitCast(OffsetPtr, CGF.VoidPtrTy), + llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)}; + llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy}; llvm::FunctionType *FnType = @@ -1386,6 +1406,8 @@ llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback"); + // Disables tail call elimination, to prevent the current stack frame from + // disappearing from the stack trace. CGF.CurFn->addFnAttr("disable-tail-calls", "true"); CGF.EmitNounwindRuntimeCall(Fn, Args); } @@ -1418,6 +1440,12 @@ EnterCXXTryStmt(*cast(Body), true); EmitAsanPrologueOrEpilogue(false); + // Insert memory-poisoning instrumentation, before final clean ups, + // to ensure this class's members are protected from invalid access. + if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor + && SanOpts.has(SanitizerKind::Memory)) + EmitDtorSanitizerCallback(*this, Dtor); + // Enter the epilogue cleanups. RunCleanupsScope DtorEpilogue(*this); @@ -1477,11 +1505,6 @@ // Exit the try if applicable. if (isTryBody) ExitCXXTryStmt(*cast(Body), true); - - // Insert memory-poisoning instrumentation. - if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor - && SanOpts.has(SanitizerKind::Memory)) - EmitDtorSanitizerCallback(*this, Dtor); } void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) { Index: test/CodeGenCXX/sanitize-dtor-derived-class.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/sanitize-dtor-derived-class.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-optzns -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -O1 -fsanitize=memory -fsanitize-memory-use-after-dtor -disable-llvm-optzns -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s + +class Base { + public: + int x; + Base() { + x = 5; + } + virtual ~Base() { + x += 1; + } +}; + +class Derived : public Base { + public: + int y; + Derived() { + y = 10; + } + ~Derived() { + y += 1; + } +}; + +Derived d; + +// CHECK-LABEL: define {{.*}}DerivedD1Ev{{.*}} +// CHECK: call void @__sanitizer_dtor_callback +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: call void {{.*}}DerivedD2Ev +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: ret void + +// CHECK-LABEL: define {{.*}}DerivedD0Ev{{.*}} +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: call void {{.*}}DerivedD1Ev +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: ret void + +// CHECK-LABEL: define {{.*}}BaseD1Ev{{.*}} +// CHECK: call void @__sanitizer_dtor_callback +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: call void {{.*}}BaseD2Ev +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: ret void + +// CHECK-LABEL: define {{.*}}BaseD0Ev{{.*}} +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: call void {{.*}}BaseD1Ev +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: ret void + +// CHECK-LABEL: define {{.*}}BaseD2Ev{{.*}} +// CHECK: call void @__sanitizer_dtor_callback +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: ret void + +// CHECK-LABEL: define {{.*}}DerivedD2Ev{{.*}} +// CHECK: call void @__sanitizer_dtor_callback +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: ret void Index: test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp =================================================================== --- test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp +++ test/CodeGenCXX/sanitize-dtor-fn-attribute.cpp @@ -26,22 +26,28 @@ // Repressing the sanitization attribute results in no msan // instrumentation of the destructor // CHECK: define {{.*}}No_SanD1Ev{{.*}} [[ATTRIBUTE:#[0-9]+]] -// CHECK: call void {{.*}}No_SanD2Ev // CHECK: call void @__sanitizer_dtor_callback +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: call void {{.*}}No_SanD2Ev +// CHECK-NOT: call void @__sanitizer_dtor_callback // CHECK: ret void // CHECK-ATTR: define {{.*}}No_SanD1Ev{{.*}} [[ATTRIBUTE:#[0-9]+]] +// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback // CHECK-ATTR: call void {{.*}}No_SanD2Ev // CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback // CHECK-ATTR: ret void // CHECK: define {{.*}}No_SanD2Ev{{.*}} [[ATTRIBUTE:#[0-9]+]] -// CHECK: call void {{.*}}Vector // CHECK: call void @__sanitizer_dtor_callback +// CHECK-NOT: call void @__sanitizer_dtor_callback +// CHECK: call void {{.*}}Vector +// CHECK-NOT: call void @__sanitizer_dtor_callback // CHECK: ret void // CHECK-ATTR: define {{.*}}No_SanD2Ev{{.*}} [[ATTRIBUTE:#[0-9]+]] +// CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback // CHECK-ATTR: call void {{.*}}Vector // CHECK-ATTR-NOT: call void @__sanitizer_dtor_callback // CHECK-ATTR: ret void