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