nmusgrave updated this revision to Diff 32608.
nmusgrave added a comment.
- More complex testing for destruction order. Tests class with base, virtual
base, trivial, and nontrivial member to ensure destruction order is correct.
http://reviews.llvm.org/D12022
Files:
lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGClass.cpp
test/CodeGenCXX/sanitize-dtor-repress-aliasing.cpp
Index: test/CodeGenCXX/sanitize-dtor-repress-aliasing.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/sanitize-dtor-repress-aliasing.cpp
@@ -0,0 +1,84 @@
+// 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
+
+template <class T>
+class Vector {
+public:
+ int size;
+ ~Vector() {}
+};
+
+// 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 VirtualBase {
+ int y;
+ VirtualBase() { y = 10; }
+ virtual ~VirtualBase() {}
+};
+
+struct Derived : public Base, public virtual VirtualBase {
+ int z;
+ Vector<int> v;
+ Derived() { z = 10; }
+ ~Derived() {}
+};
+
+Derived d;
+// Destruction order:
+// Derived: int, Vector, Base, VirtualBase
+
+// 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*)
+
+// CHECK-LABEL: define {{.*}}ZN7DerivedD1Ev
+// CHECK: call void {{.*}}ZN7DerivedD2Ev
+// CHECK: call void {{.*}}ZN11VirtualBaseD2Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN7DerivedD0Ev
+// CHECK: call void {{.*}}ZN7DerivedD1Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN11VirtualBaseD1Ev
+// CHECK: call void {{.*}}ZN11VirtualBaseD2Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN11VirtualBaseD0Ev
+// CHECK: call void {{.*}}ZN11VirtualBaseD1Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN11VirtualBaseD2Ev
+// CHECK: call void {{.*}}sanitizer_dtor_callback(i8* %{{[0-9]*}}, i64 4)
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN4BaseD1Ev
+// CHECK: call void {{.*}}ZN4BaseD2Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN4BaseD0Ev
+// CHECK: call void {{.*}}ZN4BaseD1Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN4BaseD2Ev
+// CHECK: call void {{.*}}sanitizer_dtor_callback(i8* %{{[0-9]*}}, i64 4)
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN7DerivedD2Ev
+// CHECK: call void {{.*}}ZN6VectorIiED1Ev
+// CHECK: call void {{.*}}sanitizer_dtor_callback
+// CHECK: call void {{.*}}ZN4BaseD2Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define {{.*}}ZN6VectorIiED2Ev
+// CHECK: call void {{.*}}sanitizer_dtor_callback(i8* %{{[0-9]*}}, i64 4)
+// CHECK: ret void
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<CXXDestructorDecl>(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<SanitizeDtor>(NormalCleanup, DD);
+
// Destroy direct fields.
for (const auto *Field : ClassDecl->fields()) {
QualType type = Field->getType();
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
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits