Index: lib/CodeGen/CGClass.cpp =================================================================== --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -1361,6 +1361,29 @@ return true; } +// Generates function call for handling object poisoning, passing in +// references to 'this' and its size as arguments. +static void EmitDtorSanitizerCallback(CodeGenFunction &CGF, + const CXXDestructorDecl *Dtor) { + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(Dtor->getParent()); + + 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 = + llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false); + llvm::Value *Fn = + CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback"); + CGF.EmitNounwindRuntimeCall(Fn, Args); +} + /// EmitDestructorBody - Emits the body of the current destructor. void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { const CXXDestructorDecl *Dtor = cast(CurGD.getDecl()); @@ -1448,6 +1471,10 @@ // Exit the try if applicable. if (isTryBody) ExitCXXTryStmt(*cast(Body), true); + + // Insert memory-poisoning instrumentation. + if (CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor) + EmitDtorSanitizerCallback(*this, Dtor); } void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) { Index: test/CodeGenCXX/sanitize-dtor-callback.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/sanitize-dtor-callback.cpp @@ -0,0 +1,22 @@ +// Test -fsanitize-memory-use-after-dtor +// RUN: %clang_cc1 -fsanitize=memory -fsanitize-memory-use-after-dtor -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fsanitize=memory -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s -check-prefix=NO_DTOR_CHECK + +struct Simple { + int x; + ~Simple() {} +}; + +int main() { + Simple s; + s.~Simple(); +} +// Simple internal member is poisoned by compiler-generated dtor +// CHECK-LABEL: @_ZN6SimpleD2Ev +// CHECK: call void @__sanitizer_dtor_callback +// CHECK: ret void + +// Compiling without the flag does not generate member-poisoning dtor +// NO_DTOR_CHECK-LABEL: @_ZN6SimpleD2Ev +// NO_DTOR_CHECK-NOT: call void @sanitizer_dtor_callback +// NO_DTOR_CHECK: ret void