Index: lib/CodeGen/CGCXX.cpp =================================================================== --- lib/CodeGen/CGCXX.cpp +++ lib/CodeGen/CGCXX.cpp @@ -31,6 +31,16 @@ /// Try to emit a base destructor as an alias to its primary /// base-class destructor. bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { + /* + // If sanitizing memory to check for use-after-dtor, do not emit as + // an alias, unless this class owns no members. + CodeGenFunction CGF(*this); + const ASTRecordLayout &Layout = + Context.getASTRecordLayout(D->getParent()); + */ + if ((getCodeGenOpts().SanitizeMemoryUseAfterDtor))// && CGF.SanOpts.has(SanitizerKind::Memory)) || Layout.getFieldCount() == 0) + return true; + if (!getCodeGenOpts().CXXCtorDtorAliases) return true; @@ -113,7 +123,12 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, GlobalDecl TargetDecl, bool InEveryTU) { - if (!getCodeGenOpts().CXXCtorDtorAliases) + // If sanitizing memory to check for use-after-dtor, do not emit as + // an alias, unless this class owns no members. + if (getCodeGenOpts().SanitizeMemoryUseAfterDtor) + return true; + + if(!getCodeGenOpts().CXXCtorDtorAliases) return true; // The alias will use the linkage of the referent. If we can't Index: lib/CodeGen/CGClass.cpp =================================================================== --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -1367,52 +1367,6 @@ return true; } -// Generates function call for handling object poisoning, passing in -// references to 'this' and its size as arguments. -// Disables tail call elimination, to prevent the current stack frame from -// disappearing from the stack trace. -static void EmitDtorSanitizerCallback(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor) { - const ASTRecordLayout &Layout = - CGF.getContext().getASTRecordLayout(Dtor->getParent()); - - // Nothing to poison - if(Layout.getFieldCount() == 0) - return; - - // 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; - 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(); - - llvm::Value *Args[] = { - CGF.Builder.CreateBitCast(OffsetPtr, CGF.VoidPtrTy), - llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)}; - - 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"); - - // 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); -} - /// EmitDestructorBody - Emits the body of the current destructor. void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { const CXXDestructorDecl *Dtor = cast(CurGD.getDecl()); @@ -1492,12 +1446,6 @@ if (getLangOpts().AppleKext) CurFn->addFnAttr(llvm::Attribute::AlwaysInline); - // 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); - break; } @@ -1586,6 +1534,59 @@ flags.isForNormalCleanup() && useEHCleanupForArray); } }; + +class SanitizeDtor : public EHScopeStack::Cleanup { + const CXXDestructorDecl *Dtor; + public: + SanitizeDtor(const CXXDestructorDecl *Dtor) : Dtor(Dtor) {} + + // Generate function call for handling object poisoning. + // Disables tail call elimination, to prevent the current stack frame + // from disappearing from the stack trace. + void Emit(CodeGenFunction &CGF, Flags flags) override { + // Check flags to determine if allowed to emit. + if (!CGF.CGM.getCodeGenOpts().SanitizeMemoryUseAfterDtor || + !CGF.SanOpts.has(SanitizerKind::Memory)) + return; + + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(Dtor->getParent()); + + // Nothing to poison + if (Layout.getFieldCount() == 0) + return; + + // Construct pointer to region to begin poisoning, and calculate poison + // size, so that only members declared in this class are poisoned. + ASTContext &Context = CGF.getContext(); + llvm::ConstantInt *OffsetSizePtr = llvm::ConstantInt::get( + CGF.SizeTy, + Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity()); + + llvm::Value *OffsetPtr = CGF.Builder.CreateGEP( + CGF.Builder.CreateBitCast(CGF.LoadCXXThis(), CGF.Int8PtrTy), + OffsetSizePtr); + + CharUnits::QuantityType PoisonSize = + Layout.getNonVirtualSize().getQuantity() - + Context.toCharUnitsFromBits(Layout.getFieldOffset(0)).getQuantity(); + + // Pass in void pointer and size of region as arguments to runtime function + llvm::Value *Args[] = {CGF.Builder.CreateBitCast(OffsetPtr, CGF.VoidPtrTy), + llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)}; + + 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"); + // Prevent the current stack frame from disappearing from the stack trace. + CGF.CurFn->addFnAttr("disable-tail-calls", "true"); + + CGF.EmitNounwindRuntimeCall(Fn, Args); + } +}; } /// \brief Emit all code that comes at the end of class's @@ -1658,6 +1659,8 @@ /*BaseIsVirtual*/ false); } + EHStack.pushCleanup(NormalCleanup, DD); + // Destroy direct fields. for (const auto *Field : ClassDecl->fields()) { QualType type = Field->getType(); Index: test/CodeGenCXX/sanitize-dtor-repress-aliasing.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/sanitize-dtor-repress-aliasing.cpp @@ -0,0 +1,26 @@ +// Test -fsanitize-memory-use-after-dtor +// RUN: %clang_cc1 -fsanitize=memory -O0 -fsanitize-memory-use-after-dtor -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fsanitize=memory -O1 -fsanitize-memory-use-after-dtor -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -fsanitize=memory -O2 -fsanitize-memory-use-after-dtor -std=c++11 -triple=x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s + +// Virtual function table for the derived class only contains +// its own destructors, with no aliasing to base class dtors. +struct Base { + int x; + Base() { x = 5; } + virtual ~Base() {} +}; + +struct Derived : public Base { + int y; + Derived() { y = 10; } + ~Derived() {} +}; + +Derived d; + +// Declaration of virtual function table +// CHECK: $_ZTV7Derived = comdat any + +// Definition of virtual function table +// CHECK: @_ZTV7Derived = {{.*}}(void (%struct.Derived*)* @_ZN7DerivedD1Ev to i8*){{.*}}(void (%struct.Derived*)* @_ZN7DerivedD0Ev to i8*)